





#if defined(__GNUG__) && !defined(__APPLE__)
#pragma implementation "treelistctrl.h"
#endif

#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif


#include <wx/app.h>
#include <wx/treebase.h>
#include <wx/timer.h>
#include <wx/textctrl.h>
#include <wx/imaglist.h>
#include <wx/settings.h>
#include <wx/dcclient.h>
#include <wx/dcscreen.h>
#include <wx/scrolwin.h>
#include <wx/dcmemory.h>
#include <wx/renderer.h>
#include <wx/apptrait.h>
#include <wx/dcbuffer.h>
#include <wx/tooltip.h>
#include <wx/hashmap.h>

#ifdef __WXMAC__
#if wxCHECK_VERSION(3, 0, 0)
#include "wx/osx/private.h"
#else
#include "wx/mac/private.h"
#endif
#endif

#include "wx/treelistctrl.h"

#include <wx/log.h>
#include <wx/msgdlg.h>



class wxTreeListItem;
class wxTreeListItemCellAttr;

WX_DEFINE_ARRAY_PTR(wxTreeListItem *, wxArrayTreeListItems);

#include <wx/dynarray.h>
WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo);
#include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo);


WX_DECLARE_HASH_MAP(int, wxTreeListItemCellAttr *, wxIntegerHash, wxIntegerEqual, wxTreeListItemCellAttrHash);



static const int NO_IMAGE = -1;

static const int LINEHEIGHT = 10;
static const int LINEATROOT = 5;
static const int MARGIN = 2;
static const int MININDENT = 16;
static const int BTNWIDTH = 9;
static const int BTNHEIGHT = 9;
static const int EXTRA_WIDTH = 4;
static const int EXTRA_HEIGHT = 4;
static const int HEADER_OFFSET_X = 0;
static const int HEADER_OFFSET_Y = 1;

static const int DRAG_TIMER_TICKS = 250;
static const int FIND_TIMER_TICKS = 500;
static const int RENAME_TIMER_TICKS = 250;

const wxChar* wxTreeListCtrlNameStr = _T("treelistctrl");

static wxTreeListColumnInfo wxInvalidTreeListColumnInfo;




class  wxTreeListHeaderWindow : public wxWindow {
  protected:
    wxTreeListMainWindow *m_owner;
    const wxCursor *m_currentCursor;
    const wxCursor *m_resizeCursor;
    bool m_isDragging;


    int m_column;


    int m_currentX;



    int m_minX;

    wxArrayTreeListColumnInfo m_columns;


    int m_total_col_width;

    #if wxCHECK_VERSION_FULL(2, 7, 0, 1)

    int m_hotTrackCol;
    int XToCol(int x);
    void RefreshColLabel(int col);
    #endif

  public:
    wxTreeListHeaderWindow();

    wxTreeListHeaderWindow(wxWindow *win,
                           wxWindowID id,
                           wxTreeListMainWindow *owner,
                           const wxPoint &pos = wxDefaultPosition,
                           const wxSize &size = wxDefaultSize,
                           long style = 0,
                           const wxString &name = _T("wxtreelistctrlcolumntitles"));

    virtual ~wxTreeListHeaderWindow();

    void DoDrawRect(wxDC *dc, int x, int y, int w, int h);
    void DrawCurrent();
    void AdjustDC(wxDC& dc);

    void OnPaint(wxPaintEvent &event);
    void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; }
    void OnMouse(wxMouseEvent &event);
    void OnSetFocus(wxFocusEvent &event);


    int GetWidth() const { return m_total_col_width; }


    int GetColumnCount() const { return (int)m_columns.GetCount(); }

    void AddColumn(const wxTreeListColumnInfo& colInfo);

    void InsertColumn(int before, const wxTreeListColumnInfo& colInfo);

    void RemoveColumn(int column);


    const wxTreeListColumnInfo& GetColumn(int column) const {
      wxCHECK_MSG((column >= 0) && (column < GetColumnCount()),
                  wxInvalidTreeListColumnInfo, _T("Invalid column"));
      return m_columns[column];
    }
    wxTreeListColumnInfo& GetColumn(int column) {
      wxCHECK_MSG((column >= 0) && (column < GetColumnCount()),
                  wxInvalidTreeListColumnInfo, _T("Invalid column"));
      return m_columns[column];
    }
    void SetColumn(int column, const wxTreeListColumnInfo& info);

    wxString GetColumnText(int column) const {
      wxCHECK_MSG((column >= 0) && (column < GetColumnCount()),
                  wxEmptyString, _T("Invalid column"));
      return m_columns[column].GetText();
    }
    void SetColumnText(int column, const wxString& text) {
      wxCHECK_RET((column >= 0) && (column < GetColumnCount()),
                  _T("Invalid column"));
      m_columns[column].SetText(text);
    }

    int GetColumnAlignment(int column) const {
      wxCHECK_MSG((column >= 0) && (column < GetColumnCount()),
                  wxALIGN_LEFT, _T("Invalid column"));
      return m_columns[column].GetAlignment();
    }
    void SetColumnAlignment(int column, int flag) {
      wxCHECK_RET((column >= 0) && (column < GetColumnCount()),
                  _T("Invalid column"));
      m_columns[column].SetAlignment(flag);
    }

    int GetColumnWidth(int column) const {
      wxCHECK_MSG((column >= 0) && (column < GetColumnCount()),
                  -1, _T("Invalid column"));
      return m_columns[column].GetWidth();
    }
    void SetColumnWidth(int column, int width);

    bool IsColumnEditable(int column) const {
      wxCHECK_MSG((column >= 0) && (column < GetColumnCount()),
                  false, _T("Invalid column"));
      return m_columns[column].IsEditable();
    }

    bool IsColumnShown(int column) const {
      wxCHECK_MSG((column >= 0) && (column < GetColumnCount()),
                  true, _T("Invalid column"));
      return m_columns[column].IsShown();
    }


    bool m_dirty;

  private:

    void Init();

    void SendListEvent(wxEventType type, wxPoint pos);

    DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow)
    DECLARE_EVENT_TABLE()
};



class wxEditTextCtrl;



class  wxTreeListMainWindow: public wxScrolledWindow {
  public:


    wxTreeListMainWindow() { Init(); }

    wxTreeListMainWindow(wxTreeListCtrl *parent, wxWindowID id = -1,
                         const wxPoint& pos = wxDefaultPosition,
                         const wxSize& size = wxDefaultSize,
                         long style = wxTR_DEFAULT_STYLE,
                         const wxValidator &validator = wxDefaultValidator,
                         const wxString& name = _T("wxtreelistmainwindow")) {
      Init();
      Create(parent, id, pos, size, style, validator, name);
    }

    virtual ~wxTreeListMainWindow();

    bool Create(wxTreeListCtrl *parent, wxWindowID id = -1,
                const wxPoint& pos = wxDefaultPosition,
                const wxSize& size = wxDefaultSize,
                long style = wxTR_DEFAULT_STYLE,
                const wxValidator &validator = wxDefaultValidator,
                const wxString& name = _T("wxtreelistctrl"));





    bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL); }


    size_t GetCount() const;




    unsigned int GetIndent() const { return m_indent; }
    void SetIndent(unsigned int indent);


    unsigned int GetLineSpacing() const { return m_linespacing; }
    void SetLineSpacing(unsigned int spacing);













    wxImageList *GetImageList() const { return m_imageListNormal; }
    wxImageList *GetStateImageList() const { return m_imageListState; }
    wxImageList *GetButtonsImageList() const { return m_imageListButtons; }

    void SetImageList(wxImageList *imageList);
    void SetStateImageList(wxImageList *imageList);
    void SetButtonsImageList(wxImageList *imageList);
    void AssignImageList(wxImageList *imageList);
    void AssignStateImageList(wxImageList *imageList);
    void AssignButtonsImageList(wxImageList *imageList);

    void SetToolTip(const wxString& tip);
    void SetToolTip(wxToolTip *tip);
    void SetItemToolTip(const wxTreeItemId& item, const wxString &tip);








    wxString GetItemText(const wxTreeItemId& item, int column) const;
    wxString GetItemText(wxTreeItemData* item, int column) const;


    int GetItemImage(const wxTreeItemId& item,             wxTreeItemIcon which = wxTreeItemIcon_Normal) const  { return GetItemImage(item, GetMainColumn(), which); }
    int GetItemImage(const wxTreeItemId& item, int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const;


    wxTreeItemData *GetItemData(const wxTreeItemId& item) const;
    wxTreeItemData *GetItemData(const wxTreeItemId& item, int column) const;

    bool GetItemBold(const wxTreeItemId& item)             const;
    bool GetItemBold(const wxTreeItemId& item, int column) const;

    wxColour GetItemTextColour(const wxTreeItemId& item)             const;
    wxColour GetItemTextColour(const wxTreeItemId& item, int column) const;

    wxColour GetItemBackgroundColour(const wxTreeItemId& item)             const;
    wxColour GetItemBackgroundColour(const wxTreeItemId& item, int column) const;

    wxFont GetItemFont(const wxTreeItemId& item) const;
    wxFont GetItemFont(const wxTreeItemId& item, int column) const;










    void SetItemHasChildren(const wxTreeItemId& item, bool has = true);


    void SetItemText(const wxTreeItemId& item, int column, const wxString& text);


    void SetItemImage(const wxTreeItemId& item,             int image, wxTreeItemIcon which = wxTreeItemIcon_Normal) { SetItemImage(item, GetMainColumn(), image, which); }
    void SetItemImage(const wxTreeItemId& item, int column, int image, wxTreeItemIcon which = wxTreeItemIcon_Normal);


    void SetItemData(const wxTreeItemId& item,             wxTreeItemData *data);
    void SetItemData(const wxTreeItemId& item, int column, wxTreeItemData *data);


    void SetItemBold(const wxTreeItemId& item,             bool bold = true);
    void SetItemBold(const wxTreeItemId& item, int column, bool bold = true);


    void SetItemTextColour(const wxTreeItemId& item,             const wxColour& colour);
    void SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour);


    void SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour);
    void SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour);


    void SetItemFont(const wxTreeItemId& item,             const wxFont& font);
    void SetItemFont(const wxTreeItemId& item, int column, const wxFont& font);







    bool IsVisible(const wxTreeItemId& item, bool fullRow, bool within = true) const;

    bool HasChildren(const wxTreeItemId& item) const;

    bool IsExpanded(const wxTreeItemId& item) const;

    bool IsSelected(const wxTreeItemId& item) const;

    bool IsBold(const wxTreeItemId& item)             const;
    bool IsBold(const wxTreeItemId& item, int column) const;




    virtual bool SetFont(const wxFont &font);



    void SetWindowStyle(const long styles);






    size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true);







    wxTreeItemId GetRootItem() const { return m_rootItem; }


    wxTreeItemId GetSelection() const { return m_selectItem; }


    size_t GetSelections(wxArrayTreeItemIds&) const;


    wxTreeItemId GetItemParent(const wxTreeItemId& item) const;









    wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
    wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
    wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
    wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;


    wxTreeItemId GetNextSibling(const wxTreeItemId& item) const;
    wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const;


    wxTreeItemId GetNext(const wxTreeItemId& item, bool fulltree = true) const;
    wxTreeItemId GetPrev(const wxTreeItemId& item, bool fulltree = true) const;


    wxTreeItemId GetFirstExpandedItem() const;
    wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const;
    wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const;


    wxTreeItemId GetFirstVisible(bool fullRow, bool within) const;
    wxTreeItemId GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const;
    wxTreeItemId GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const;
    wxTreeItemId GetLastVisible(bool fullRow, bool within) const;





    wxTreeItemId AddRoot(const wxString& text,
                         int image = -1, int selectedImage = -1,
                         wxTreeItemData *data = NULL);


    wxTreeItemId PrependItem(const wxTreeItemId& parent,
                             const wxString& text,
                             int image = -1, int selectedImage = -1,
                             wxTreeItemData *data = NULL);


    wxTreeItemId InsertItem(const wxTreeItemId& parent,
                            const wxTreeItemId& idPrevious,
                            const wxString& text,
                            int image = -1, int selectedImage = -1,
                            wxTreeItemData *data = NULL);


    wxTreeItemId InsertItem(const wxTreeItemId& parent,
                            size_t index,
                            const wxString& text,
                            int image = -1, int selectedImage = -1,
                            wxTreeItemData *data = NULL);


    wxTreeItemId AppendItem(const wxTreeItemId& parent,
                            const wxString& text,
                            int image = -1, int selectedImage = -1,
                            wxTreeItemData *data = NULL);


    void Delete(const wxTreeItemId& item);


    void DeleteChildren(const wxTreeItemId& item);


    void DeleteRoot();


    void Expand(const wxTreeItemId& item);

    void ExpandAll(const wxTreeItemId& item);

    void Collapse(const wxTreeItemId& item);

    void CollapseAndReset(const wxTreeItemId& item);

    void Toggle(const wxTreeItemId& item);


    void SetCurrentItem(const wxTreeItemId& item);


    void Unselect();
    void UnselectAll();

    bool SelectItem(const wxTreeItemId& item, const wxTreeItemId& prev = (wxTreeItemId*)NULL,
                    bool unselect_others = true);
    void SelectAll();


    void EnsureVisible(const wxTreeItemId& item);

    void ScrollTo(const wxTreeItemId& item);
    void AdjustMyScrollbars();



    wxTreeItemId HitTest(const wxPoint& point)
    { int flags; int column; return HitTest(point, flags, column); }
    wxTreeItemId HitTest(const wxPoint& point, int& flags)
    { int column; return HitTest(point, flags, column); }
    wxTreeItemId HitTest(const wxPoint& point, int& flags, int& column);



    bool GetBoundingRect(const wxTreeItemId& item,
                         wxRect& rect,
                         bool textOnly = false) const;




    void EditLabel(const wxTreeItemId& item, int column);
    void EndEdit(bool isCancelled);






    virtual int OnCompareItems(const wxTreeItemId& item1,
                               const wxTreeItemId& item2);



    void SortChildren(const wxTreeItemId& item, int column, bool reverseOrder);


    wxTreeItemId FindItem(const wxTreeItemId& item, int column, const wxString& str, int mode = 0);




    virtual bool SetBackgroundColour(const wxColour& colour);
    virtual bool SetForegroundColour(const wxColour& colour);


    void SetDragItem(const wxTreeItemId& item = (wxTreeItemId*)NULL);


    void OnPaint(wxPaintEvent &event);
    void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; }
    void OnSetFocus(wxFocusEvent &event);
    void OnKillFocus(wxFocusEvent &event);
    void OnChar(wxKeyEvent &event);
    void OnMouse(wxMouseEvent &event);
    void OnIdle(wxIdleEvent &event);
    void OnScroll(wxScrollWinEvent& event);
    void OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event)) { ;; }


    int GetColumnCount() const
    { return m_owner->GetHeaderWindow()->GetColumnCount(); }

    void SetMainColumn(int column)
    { if((column >= 0) && (column < GetColumnCount())) m_main_column = column; }

    int GetMainColumn() const { return m_main_column; }
    int GetCurrentColumn() const { return m_curColumn >= 0 ? m_curColumn : m_main_column; }

    int GetBestColumnWidth(int column, wxTreeItemId parent = wxTreeItemId());
    int GetItemWidth(int column, wxTreeListItem *item);

    void SetFocus();

  protected:
    wxTreeListCtrl* m_owner;

    int m_main_column;

    friend class wxTreeListItem;
    friend class wxTreeListRenameTimer;
    friend class wxEditTextCtrl;

    wxFont               m_normalFont;
    wxFont               m_boldFont;

    wxTreeListItem       *m_rootItem;
    wxTreeListItem       *m_curItem;
    wxTreeListItem       *m_shiftItem;
    wxTreeListItem       *m_selectItem;

    int                  m_curColumn;
    int                  m_sortColumn;
    bool                 m_ReverseSortOrder;

    int                  m_btnWidth, m_btnWidth2;
    int                  m_btnHeight, m_btnHeight2;
    int                  m_imgWidth, m_imgWidth2;
    int                  m_imgHeight, m_imgHeight2;
    unsigned short       m_indent;
    int                  m_lineHeight;
    unsigned short       m_linespacing;
    wxPen                m_dottedPen;
    wxBrush             *m_hilightBrush,
                        *m_hilightUnfocusedBrush;
    bool                 m_hasFocus;
  public:
    bool                 m_dirty;
  protected:
    bool                 m_ownsImageListNormal,
                         m_ownsImageListState,
                         m_ownsImageListButtons;
    bool                 m_lastOnSame;
    bool                 m_left_down_selection;

    wxImageList         *m_imageListNormal,
                        *m_imageListState,
                        *m_imageListButtons;

    bool                 m_isDragStarted;
    bool                 m_isDragging;
    wxPoint              m_dragStartPos;
    wxTreeListItem      *m_dragItem;
    int                  m_dragCol;

    wxTreeListItem       *m_editItem;
    wxTimer             *m_editTimer;
    bool                 m_editAccept;
    wxString             m_editRes;
    int                  m_editCol;
    wxEditTextCtrl      *m_editControl;


    wxTimer             *m_findTimer;
    wxString             m_findStr;

    bool                 m_isItemToolTip;
    wxString             m_toolTip;
    wxTreeListItem      *m_toolTipItem;


    void Init();


    wxTreeItemId DoInsertItem(const wxTreeItemId& parent,
                              size_t previous,
                              const wxString& text,
                              int image, int selectedImage,
                              wxTreeItemData *data);
    void DoDeleteItem(wxTreeListItem *item);
    void SetCurrentItem(wxTreeListItem *item);
    bool HasButtons(void) const
    { return (m_imageListButtons) || HasFlag(wxTR_TWIST_BUTTONS | wxTR_HAS_BUTTONS); }

    void CalculateLineHeight();
    int  GetLineHeight(wxTreeListItem *item) const;
    void PaintLevel(wxTreeListItem *item, wxDC& dc, int level, int &y,
                    int x_maincol);
    void PaintItem(wxTreeListItem *item, wxDC& dc);

    void CalculateLevel(wxTreeListItem *item, wxDC &dc, int level, int &y,
                        int x_maincol);
    void CalculatePositions();
    void CalculateSize(wxTreeListItem *item, wxDC &dc);

    void RefreshSubtree(wxTreeListItem *item);
    void RefreshLine(wxTreeListItem *item);

    void RefreshSelected();

    void RefreshSelectedUnder(wxTreeListItem *item);

    void OnRenameTimer();
    void OnRenameAccept(bool isCancelled);

    void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const;
    bool TagAllChildrenUntilLast(wxTreeListItem *crt_item, wxTreeListItem *last_item);
    bool TagNextChildren(wxTreeListItem *crt_item, wxTreeListItem *last_item);
    void UnselectAllChildren(wxTreeListItem *item);
    bool SendEvent(wxEventType event_type, wxTreeListItem *item = NULL, wxTreeEvent *event = NULL);

  private:
    DECLARE_EVENT_TABLE()
    DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow)
};




class  wxTreeListRenameTimer: public wxTimer {
  public:
    wxTreeListRenameTimer(wxTreeListMainWindow *owner);

    void Notify();

  private:
    wxTreeListMainWindow   *m_owner;
};




class  wxEditTextCtrl: public wxTextCtrl {
  public:
    wxEditTextCtrl(wxWindow *parent,
                   const wxWindowID id,
                   bool *accept,
                   wxString *res,
                   wxTreeListMainWindow *owner,
                   const wxString &value = wxEmptyString,
                   const wxPoint &pos = wxDefaultPosition,
                   const wxSize &size = wxDefaultSize,
                   int style = 0,
                   const wxValidator& validator = wxDefaultValidator,
                   const wxString &name = wxTextCtrlNameStr);
    ~wxEditTextCtrl();

    virtual bool Destroy();
    void EndEdit(bool isCancelled);
    void SetOwner(wxTreeListMainWindow *owner) { m_owner = owner; }

    void OnChar(wxKeyEvent &event);
    void OnKeyUp(wxKeyEvent &event);
    void OnKillFocus(wxFocusEvent &event);


  private:
    wxTreeListMainWindow  *m_owner;
    bool               *m_accept;
    wxString           *m_res;
    wxString            m_startValue;
    bool                m_finished;

    DECLARE_EVENT_TABLE()
};





class  wxTreeListItemCellAttr {
  public:
    wxTreeListItemCellAttr() {
      m_attr = NULL;
      m_data = NULL;
      m_isBold = 0;
      m_isBoldSet = 0;
      m_ownsAttr = 0;
      m_image = NO_IMAGE;
    };
    ~wxTreeListItemCellAttr() {
      if(m_ownsAttr)
        delete m_attr;
    }


    wxTreeItemAttr      *m_attr;


    wxTreeItemData      *m_data;
    short                m_image;
    int                  m_isBold : 1;
    int                  m_isBoldSet : 1;
    int                  m_ownsAttr : 1;
};




class  wxTreeListItem {
  public:


    wxTreeListItem() { m_toolTip = NULL; }
    wxTreeListItem(wxTreeListMainWindow *owner,
                   wxTreeListItem *parent,
                   const wxArrayString& text,
                   int image,
                   int selImage,
                   wxTreeItemData *data);

    ~wxTreeListItem();




    wxArrayTreeListItems& GetChildren() { return m_children; }


    const wxString GetText(int column) const {
      if(IsVirtual())
        return m_owner->GetItemText(m_props_row.m_data, column);
      if(column < (signed)m_text.GetCount())
        return m_text[column];
      return wxEmptyString;
    };

    int GetImage(wxTreeItemIcon which = wxTreeItemIcon_Normal) const { return m_images[which]; };
    int GetImage(int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const {
      if(column == m_owner->GetMainColumn())
        return m_images[which];
      wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find(column);
      if(entry == m_props_cell.end())
        return NO_IMAGE;
      return entry->second->m_image;
    };


    wxTreeItemData *GetData()           const { return m_props_row.m_data; };
    wxTreeItemData *GetData(int column) const {
      wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find(column);
      if(entry == m_props_cell.end())
        return NULL;
      return entry->second->m_data;
    };

    const wxString * GetToolTip() const  {  return m_toolTip;  };



    int GetCurrentImage() const;




    void SetHasPlus(bool has = true) { m_hasPlus = has; };

    void SetText(int column, const wxString& text) {
      if(column < (int)m_text.GetCount())
        m_text[column] = text;

      else if(column < m_owner->GetColumnCount()) {
        int howmany = m_owner->GetColumnCount();
        for(int i = (int)m_text.GetCount(); i < howmany; ++i)
          m_text.Add(wxEmptyString);
        m_text[column] = text;
      }
    };
    void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; };
    void SetImage(int column, int image, wxTreeItemIcon which) {
      if(column == m_owner->GetMainColumn())
        m_images[which] = image;
      else {
        wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find(column);
        if(entry == m_props_cell.end()) {
          m_props_cell[column] = new wxTreeListItemCellAttr();
          m_props_cell[column]->m_image = image;
        } else
          entry->second->m_image = image;
      }
    };


    void SetData(wxTreeItemData *data) { m_props_row.m_data = data; };
    void SetData(int column, wxTreeItemData *data) {
      wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find(column);
      if(entry == m_props_cell.end()) {
        m_props_cell[column] = new wxTreeListItemCellAttr();
        m_props_cell[column]->m_data = data;
      } else
        entry->second->m_data = data;
    }

    void SetBold(bool bold) { m_props_row.m_isBold = bold; }
    void SetBold(int column, bool bold) {
      wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find(column);
      if(entry == m_props_cell.end()) {
        m_props_cell[column] = new wxTreeListItemCellAttr();
        m_props_cell[column]->m_isBold = bold;
        m_props_cell[column]->m_isBoldSet = 1;
      } else {
        entry->second->m_isBold = bold;
        entry->second->m_isBoldSet = 1;
      }
    }


    void SetToolTip(const wxString &tip) {
      if(m_toolTip)  {
        delete m_toolTip;
        m_toolTip = NULL;
      }
      if(tip.length() > 0)
        m_toolTip = new wxString(tip);
    };




    bool HasChildren() const        { return !m_children.IsEmpty(); }
    bool IsSelected()  const        { return m_hasHilight != 0; }
    bool IsExpanded()  const        { return !m_isCollapsed; }
    bool HasPlus()     const        { return m_hasPlus || HasChildren(); }
    bool IsBold()      const        { return m_props_row.m_isBold; }
    bool IsBold(int column) const {
      wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find(column);
      if(entry == m_props_cell.end() || ! entry->second->m_isBoldSet)
        return IsBold();
      return (entry->second->m_isBold != 0);
    }
    bool IsVirtual()   const        { return m_owner->IsVirtual(); }



    int GetX() const { return m_x; }
    int GetY() const { return m_y; }

    void SetX(int x) { m_x = x; }
    void SetY(int y) { m_y = y; }

    int  GetHeight() const { return m_height; }
    int  GetWidth()  const { return m_width; }

    void SetHeight(int height) { m_height = height; }
    void SetWidth(int width) { m_width = width; }

    int GetTextX() const { return m_text_x; }
    void SetTextX(int text_x) { m_text_x = text_x; }

    wxTreeListItem *GetItemParent() const { return m_parent; }


    size_t GetChildrenCount(bool recursively = true) const;

    void GetSize(int &x, int &y, const wxTreeListMainWindow*);




    wxTreeListItem *HitTest(const wxPoint& point,
                            const wxTreeListMainWindow *,
                            int &flags, int& column, int level);





    void DeleteChildren();

    void Insert(wxTreeListItem *child, size_t index)
    { m_children.Insert(child, index); }

    void Expand() { m_isCollapsed = false; }
    void Collapse() { m_isCollapsed = true; }

    void SetHilight(bool set = true) { m_hasHilight = set; }







    wxTreeItemAttr *GetAttributes(int column) const {
      wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find(column);
      if(entry == m_props_cell.end())
        return GetAttributes();
      return entry->second->m_attr;
    }
    wxTreeItemAttr *GetAttributes() const { return m_props_row.m_attr; }


    wxTreeItemAttr& Attr(int column) {
      wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find(column);
      if(entry == m_props_cell.end()) {
        m_props_cell[column] = new wxTreeListItemCellAttr();
        m_props_cell[column]->m_attr = new wxTreeItemAttr;
        m_props_cell[column]->m_ownsAttr = 1;
        return *(m_props_cell[column]->m_attr);
      } else
        return *(entry->second->m_attr);
    }
    wxTreeItemAttr& Attr() {
      if(!m_props_row.m_attr) {
        m_props_row.m_attr = new wxTreeItemAttr;
        m_props_row.m_ownsAttr = 1;
      }
      return *m_props_row.m_attr;
    }


  private:
    wxTreeListMainWindow       *m_owner;

    wxArrayTreeListItems        m_children;
    wxTreeListItem             *m_parent;


    wxCoord                     m_x;
    wxCoord                     m_y;
    wxCoord                     m_text_x;
    short                       m_width;
    unsigned char               m_height;


    short                       m_images[wxTreeItemIcon_Max];

    wxString                   *m_toolTip;


    int                         m_isCollapsed : 1;
    int                         m_hasHilight  : 1;
    int                         m_hasPlus     : 1;



    wxArrayString               m_text;
    wxTreeListItemCellAttr      m_props_row;
    wxTreeListItemCellAttrHash  m_props_cell;
};






wxTreeListRenameTimer::wxTreeListRenameTimer(wxTreeListMainWindow *owner) {
  m_owner = owner;
}

void wxTreeListRenameTimer::Notify() {
  m_owner->OnRenameTimer();
}



BEGIN_EVENT_TABLE(wxEditTextCtrl, wxTextCtrl)
  EVT_CHAR(wxEditTextCtrl::OnChar)
  EVT_KEY_UP(wxEditTextCtrl::OnKeyUp)
  EVT_KILL_FOCUS(wxEditTextCtrl::OnKillFocus)
END_EVENT_TABLE()

wxEditTextCtrl::wxEditTextCtrl(wxWindow *parent,
                               const wxWindowID id,
                               bool *accept,
                               wxString *res,
                               wxTreeListMainWindow *owner,
                               const wxString &value,
                               const wxPoint &pos,
                               const wxSize &size,
                               int style,
                               const wxValidator& validator,
                               const wxString &name)
  : wxTextCtrl(parent, id, value, pos, size, style | wxSIMPLE_BORDER, validator, name) {
  m_res = res;
  m_accept = accept;
  m_owner = owner;
  (*m_accept) = false;
  (*m_res) = wxEmptyString;
  m_startValue = value;
  m_finished = false;
}

wxEditTextCtrl::~wxEditTextCtrl() {
  EndEdit(true);
}

void wxEditTextCtrl::EndEdit(bool isCancelled) {
  if(m_finished)
    return;
  m_finished = true;
  if(m_owner) {
    (*m_accept) = ! isCancelled;
    (*m_res) = isCancelled ? m_startValue : GetValue();
    m_owner->OnRenameAccept(*m_res == m_startValue);
    m_owner->m_editControl = NULL;
    m_owner->m_editItem = NULL;
    m_owner->SetFocus();
    m_owner = NULL;
  }
  Destroy();
}

bool wxEditTextCtrl::Destroy() {
  Hide();
  #if wxCHECK_VERSION(3, 0, 0)
  wxTheApp->ScheduleForDestruction(this);
  #else
  wxTheApp->GetTraits()->ScheduleForDestroy(this);
  #endif
  return true;
}

void wxEditTextCtrl::OnChar(wxKeyEvent &event) {
  if(m_finished) {
    event.Skip();
    return;
  }
  if(event.GetKeyCode() == WXK_RETURN) {
    EndEdit(false);
    return;
  }
  if(event.GetKeyCode() == WXK_ESCAPE) {
    EndEdit(true);
    return;
  }
  event.Skip();
}

void wxEditTextCtrl::OnKeyUp(wxKeyEvent &event) {
  if(m_finished) {
    event.Skip();
    return;
  }
  wxSize parentSize = m_owner->GetSize();
  wxPoint myPos = GetPosition();
  wxSize mySize = GetSize();
  int sx, sy;
  GetTextExtent(GetValue() + _T("M"), &sx, &sy);
  if(myPos.x + sx > parentSize.x)
    sx = parentSize.x - myPos.x;
  if(mySize.x > sx)
    sx = mySize.x;
  SetSize(sx, -1);
  event.Skip();
}

void wxEditTextCtrl::OnKillFocus(wxFocusEvent &event) {
  if(m_finished) {
    event.Skip();
    return;
  }
  EndEdit(false);
}



IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow);

BEGIN_EVENT_TABLE(wxTreeListHeaderWindow, wxWindow)
  EVT_PAINT(wxTreeListHeaderWindow::OnPaint)
  EVT_ERASE_BACKGROUND(wxTreeListHeaderWindow::OnEraseBackground)
  EVT_MOUSE_EVENTS(wxTreeListHeaderWindow::OnMouse)
  EVT_SET_FOCUS(wxTreeListHeaderWindow::OnSetFocus)
END_EVENT_TABLE()


void wxTreeListHeaderWindow::Init() {
  m_currentCursor = (wxCursor *) NULL;
  m_isDragging = false;
  m_dirty = false;
  m_total_col_width = 0;
  #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
  m_hotTrackCol = -1;
  #endif
  SetBackgroundStyle(wxBG_STYLE_CUSTOM);
}

wxTreeListHeaderWindow::wxTreeListHeaderWindow() {
  Init();
  m_owner = (wxTreeListMainWindow *) NULL;
  m_resizeCursor = (wxCursor *) NULL;
}

wxTreeListHeaderWindow::wxTreeListHeaderWindow(wxWindow *win,
    wxWindowID id,
    wxTreeListMainWindow *owner,
    const wxPoint& pos,
    const wxSize& size,
    long style,
    const wxString &name)
  : wxWindow(win, id, pos, size, style, name) {
  Init();
  m_owner = owner;
  m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE);
  SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
}

wxTreeListHeaderWindow::~wxTreeListHeaderWindow() {
  delete m_resizeCursor;
}

void wxTreeListHeaderWindow::DoDrawRect(wxDC *dc, int x, int y, int w, int h) {
  wxPen pen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), 1, wxSOLID);
  const int m_corner = 1;
  dc->SetBrush(*wxTRANSPARENT_BRUSH);
  #if defined( __WXMAC__  )
  dc->SetPen(pen);
  #else
  dc->SetPen(*wxBLACK_PEN);
  #endif
  dc->DrawLine(x + w - m_corner + 1, y, x + w, y + h);
  dc->DrawRectangle(x, y + h, w + 1, 1);
  #if defined( __WXMAC__  )
  pen = wxPen(wxColour(0x88, 0x88, 0x88), 1, wxSOLID);
  #endif
  dc->SetPen(pen);
  dc->DrawLine(x + w - m_corner, y, x + w - 1, y + h);
  dc->DrawRectangle(x + 1, y + h - 1, w - 2, 1);
  dc->SetPen(*wxWHITE_PEN);
  dc->DrawRectangle(x, y, w - m_corner + 1, 1);
  dc->DrawRectangle(x, y, 1, h);
  dc->DrawLine(x, y + h - 1, x + 1, y + h - 1);
  dc->DrawLine(x + w - 1, y, x + w - 1, y + 1);
}


void wxTreeListHeaderWindow::AdjustDC(wxDC& dc) {
  int xpix;
  m_owner->GetScrollPixelsPerUnit(&xpix, NULL);
  int x;
  m_owner->GetViewStart(&x, NULL);
  dc.SetDeviceOrigin(-x * xpix, 0);
}

void wxTreeListHeaderWindow::OnPaint(wxPaintEvent &WXUNUSED(event)) {
  wxAutoBufferedPaintDC dc(this);
  AdjustDC(dc);
  int x = HEADER_OFFSET_X;
  int w, h;
  GetClientSize(&w, &h);
  m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
  dc.SetBackgroundMode(wxTRANSPARENT);
  #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
  int numColumns = GetColumnCount();
  for(int i = 0; i < numColumns && x < w; i++) {
    if(!IsColumnShown(i))
      continue;
    wxHeaderButtonParams params;
    params.m_labelColour = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
    params.m_labelFont = GetFont();
    wxTreeListColumnInfo& column = GetColumn(i);
    int wCol = column.GetWidth();
    int flags = 0;
    wxRect rect(x, 0, wCol, h);
    x += wCol;
    if(i == m_hotTrackCol)
      flags |= wxCONTROL_CURRENT;
    params.m_labelText = column.GetText();
    params.m_labelAlignment = column.GetAlignment();
    int image = column.GetImage();
    wxImageList* imageList = m_owner->GetImageList();
    if((image != -1) && imageList)
      params.m_labelBitmap = imageList->GetBitmap(image);
    wxRendererNative::Get().DrawHeaderButton(this, dc, rect, flags, wxHDR_SORT_ICON_NONE, &params);
  }
  if(x < w) {
    wxRect rect(x, 0, w - x, h);
    wxRendererNative::Get().DrawHeaderButton(this, dc, rect);
  }
  #else
  dc.SetFont(GetFont());
  dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
  int numColumns = GetColumnCount();
  for(int i = 0; i < numColumns && x < w; i++) {
    if(!IsColumnShown(i))
      continue;
    wxTreeListColumnInfo& column = GetColumn(i);
    int wCol = column.GetWidth();
    int cw = wCol - 2;
    wxRect rect(x, HEADER_OFFSET_Y, cw, h - 2);
    wxRendererNative::GetDefault().DrawHeaderButton(this, dc, rect);
    int image = column.GetImage();
    int ix = -2, iy = 0;
    wxImageList* imageList = m_owner->GetImageList();
    if((image != -1) && imageList)
      imageList->GetSize(image, ix, iy);
    int text_width = 0;
    int text_x = x;
    int image_offset = cw - ix - 1;
    switch(column.GetAlignment()) {
      case wxALIGN_LEFT:
        text_x += EXTRA_WIDTH;
        cw -= ix + 2;
        break;
      case wxALIGN_RIGHT:
        dc.GetTextExtent(column.GetText(), &text_width, NULL);
        text_x += cw - text_width - EXTRA_WIDTH - MARGIN;
        image_offset = 0;
        break;
      case wxALIGN_CENTER:
        dc.GetTextExtent(column.GetText(), &text_width, NULL);
        text_x += (cw - text_width) / 2 + ix + 2;
        image_offset = (cw - text_width - ix - 2) / 2 - MARGIN;
        break;
    }
    if((image != -1) && imageList) {
      imageList->Draw(image, dc, x + image_offset,
                      HEADER_OFFSET_Y + (h - 4 - iy) / 2,
                      wxIMAGELIST_DRAW_TRANSPARENT);
    }
    wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4);
    dc.DrawText(column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT);
    x += wCol;
  }
  int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X;
  if(more_w > 0) {
    wxRect rect(x, HEADER_OFFSET_Y, more_w, h - 2);
    wxRendererNative::GetDefault().DrawHeaderButton(this, dc, rect);
  }
  #endif
}

void wxTreeListHeaderWindow::DrawCurrent() {
  int x1 = m_currentX;
  int y1 = 0;
  ClientToScreen(&x1, &y1);
  int x2 = m_currentX - 1;
  #ifdef __WXMSW__
  ++x2;
  #endif
  int y2 = 0;
  m_owner->GetClientSize(NULL, &y2);
  m_owner->ClientToScreen(&x2, &y2);
  wxScreenDC dc;
  dc.SetLogicalFunction(wxINVERT);
  dc.SetPen(wxPen(*wxBLACK, 2, wxSOLID));
  dc.SetBrush(*wxTRANSPARENT_BRUSH);
  AdjustDC(dc);
  dc.DrawLine(x1, y1, x2, y2);
  dc.SetLogicalFunction(wxCOPY);
  dc.SetPen(wxNullPen);
  dc.SetBrush(wxNullBrush);
}

#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
int wxTreeListHeaderWindow::XToCol(int x) {
  int colLeft = 0;
  int numColumns = GetColumnCount();
  for(int col = 0; col < numColumns; col++) {
    if(!IsColumnShown(col))
      continue;
    wxTreeListColumnInfo& column = GetColumn(col);
    if(x < (colLeft + column.GetWidth()))
      return col;
    colLeft += column.GetWidth();
  }
  return -1;
}

void wxTreeListHeaderWindow::RefreshColLabel(int col) {
  if(col > GetColumnCount())
    return;
  int x = 0;
  int width = 0;
  int idx = 0;
  do {
    if(!IsColumnShown(idx))
      continue;
    wxTreeListColumnInfo& column = GetColumn(idx);
    x += width;
    width = column.GetWidth();
  } while(++idx <= col);
  m_owner->CalcScrolledPosition(x, 0, &x, NULL);
  RefreshRect(wxRect(x, 0, width, GetSize().GetHeight()));
}
#endif

void wxTreeListHeaderWindow::OnMouse(wxMouseEvent &event) {
  int x;
  m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
  #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
  if(event.Moving()) {
    int col = XToCol(x);
    if(col != m_hotTrackCol) {
      RefreshColLabel(col);
      if(m_hotTrackCol >= 0)
        RefreshColLabel(m_hotTrackCol);
      m_hotTrackCol = col;
    }
  }
  if(event.Leaving() && m_hotTrackCol >= 0) {
    RefreshColLabel(m_hotTrackCol);
    m_hotTrackCol = -1;
  }
  #endif
  if(m_isDragging) {
    SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
    int w = 0;
    GetClientSize(&w, NULL);
    m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
    w -= 6;
    if(m_currentX < w)
      DrawCurrent();
    if(event.ButtonUp()) {
      m_isDragging = false;
      if(HasCapture())
        ReleaseMouse();
      m_dirty = true;
      SetColumnWidth(m_column, m_currentX - m_minX);
      Refresh();
      SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
    } else {
      m_currentX = wxMax(m_minX + 7, x);
      if(m_currentX < w)
        DrawCurrent();
    }
  } else {
    m_minX = 0;
    bool hit_border = false;
    int xpos = 0;
    int countCol = GetColumnCount();
    for(int column = 0; column < countCol; column++) {
      if(!IsColumnShown(column))
        continue;
      xpos += GetColumnWidth(column);
      m_column = column;
      if(abs(x - xpos) < 3) {
        hit_border = true;
        break;
      }
      if(x < xpos)
        break;
      m_minX = xpos;
    }
    if(event.LeftDown() || event.RightUp()) {
      m_owner->EndEdit(true);
      if(hit_border && event.LeftDown()) {
        m_isDragging = true;
        CaptureMouse();
        m_currentX = x;
        DrawCurrent();
        SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
      } else {
        wxEventType evt = event.LeftDown() ? wxEVT_COMMAND_LIST_COL_CLICK :
                          wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
        SendListEvent(evt, event.GetPosition());
      }
    } else if(event.LeftDClick() && hit_border) {
      SetColumnWidth(m_column, m_owner->GetBestColumnWidth(m_column));
      Refresh();
    } else if(event.Moving()) {
      bool setCursor;
      if(hit_border) {
        setCursor = m_currentCursor == wxSTANDARD_CURSOR;
        m_currentCursor = m_resizeCursor;
      } else {
        setCursor = m_currentCursor != wxSTANDARD_CURSOR;
        m_currentCursor = wxSTANDARD_CURSOR;
      }
      if(setCursor)
        SetCursor(*m_currentCursor);
    }
  }
}

void wxTreeListHeaderWindow::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
  m_owner->SetFocus();
}

void wxTreeListHeaderWindow::SendListEvent(wxEventType type, wxPoint pos) {
  wxWindow *parent = GetParent();
  wxListEvent le(type, parent->GetId());
  le.SetEventObject(parent);
  le.m_pointDrag = pos;
  le.m_pointDrag.y -= GetSize().y;
  le.m_col = m_column;
  parent->GetEventHandler()->ProcessEvent(le);
}

void wxTreeListHeaderWindow::AddColumn(const wxTreeListColumnInfo& colInfo) {
  m_columns.Add(colInfo);
  m_total_col_width += colInfo.GetWidth();
  m_owner->AdjustMyScrollbars();
  m_owner->m_dirty = true;
}

void wxTreeListHeaderWindow::SetColumnWidth(int column, int width) {
  wxCHECK_RET((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
  m_total_col_width -= m_columns[column].GetWidth();
  m_columns[column].SetWidth(width);
  m_total_col_width += width;
  m_owner->AdjustMyScrollbars();
  m_owner->m_dirty = true;
}

void wxTreeListHeaderWindow::InsertColumn(int before, const wxTreeListColumnInfo& colInfo) {
  wxCHECK_RET((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
  m_columns.Insert(colInfo, before);
  m_total_col_width += colInfo.GetWidth();
  m_owner->AdjustMyScrollbars();
  m_owner->m_dirty = true;
}

void wxTreeListHeaderWindow::RemoveColumn(int column) {
  wxCHECK_RET((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
  m_total_col_width -= m_columns[column].GetWidth();
  m_columns.RemoveAt(column);
  m_owner->AdjustMyScrollbars();
  m_owner->m_dirty = true;
}

void wxTreeListHeaderWindow::SetColumn(int column, const wxTreeListColumnInfo& info) {
  wxCHECK_RET((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
  int w = m_columns[column].GetWidth();
  m_columns[column] = info;
  if(w != info.GetWidth()) {
    m_total_col_width += info.GetWidth() - w;
    m_owner->AdjustMyScrollbars();
  }
  m_owner->m_dirty = true;
}



wxTreeListItem::wxTreeListItem(wxTreeListMainWindow *owner,
                               wxTreeListItem *parent,
                               const wxArrayString& text,
                               int image, int selImage,
                               wxTreeItemData *data)
  : m_text(text) {
  m_images[wxTreeItemIcon_Normal] = image;
  m_images[wxTreeItemIcon_Selected] = selImage;
  m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
  m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
  m_props_row.m_data = data;
  m_toolTip = NULL;
  m_x = 0;
  m_y = 0;
  m_text_x = 0;
  m_isCollapsed = true;
  m_hasHilight = false;
  m_hasPlus = false;
  m_owner = owner;
  m_parent = parent;
  m_width = 0;
  m_height = 0;
}

wxTreeListItem::~wxTreeListItem() {
  if(m_toolTip)
    delete m_toolTip;
  wxTreeListItemCellAttrHash::iterator entry = m_props_cell.begin();
  while(entry != m_props_cell.end()) {
    if(entry->second)
      delete entry->second;
    entry++;
  }
  wxASSERT_MSG(m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
}

void wxTreeListItem::DeleteChildren() {
  m_children.Empty();
}

size_t wxTreeListItem::GetChildrenCount(bool recursively) const {
  size_t count = m_children.Count();
  if(!recursively)
    return count;
  size_t total = count;
  for(size_t n = 0; n < count; ++n)
    total += m_children[n]->GetChildrenCount();
  return total;
}

void wxTreeListItem::GetSize(int &x, int &y, const wxTreeListMainWindow *theButton) {
  int bottomY = m_y + theButton->GetLineHeight(this);
  if(y < bottomY)
    y = bottomY;
  int width = m_x +  m_width;
  if(x < width)
    x = width;
  if(IsExpanded()) {
    size_t count = m_children.Count();
    for(size_t n = 0; n < count; ++n)
      m_children[n]->GetSize(x, y, theButton);
  }
}

wxTreeListItem *wxTreeListItem::HitTest(const wxPoint& point,
                                        const wxTreeListMainWindow *theCtrl,
                                        int &flags, int& column, int level) {
  flags = 0;
  column = -1;
  if(!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
    wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
    if(point.x > header_win->GetWidth())
      return (wxTreeListItem*) NULL;
    for(int x = 0, j = 0; j < theCtrl->GetColumnCount(); ++j) {
      if(!header_win->IsColumnShown(j))
        continue;
      int w = header_win->GetColumnWidth(j);
      if(point.x >= x && point.x < x + w) {
        column = j;
        break;
      }
      x += w;
    }
    int h = theCtrl->GetLineHeight(this);
    if((point.y >= m_y) && (point.y <= m_y + h)) {
      int y_mid = m_y + h / 2;
      if(point.y < y_mid)
        flags |= wxTREE_HITTEST_ONITEMUPPERPART;

      else
        flags |= wxTREE_HITTEST_ONITEMLOWERPART;
      if(HasPlus() && theCtrl->HasButtons()) {
        int bntX = m_x - theCtrl->m_btnWidth2;
        int bntY = y_mid - theCtrl->m_btnHeight2;
        if((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
            (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
          flags |= wxTREE_HITTEST_ONITEMBUTTON;
          return this;
        }
      }
      if(theCtrl->m_imgWidth > 0) {
        int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN;
        int imgY = y_mid - theCtrl->m_imgHeight2;
        if((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
            (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
          flags |= wxTREE_HITTEST_ONITEMICON;
          return this;
        }
      }
      if((point.x >= m_text_x) && (point.x <= (m_text_x + m_width))) {
        flags |= wxTREE_HITTEST_ONITEMLABEL;
        return this;
      }
      if(point.x < m_x) {
        flags |= wxTREE_HITTEST_ONITEMINDENT;
        return this;
      }
      int end = 0;
      for(int i = 0; i <= theCtrl->GetMainColumn(); ++i)
        end += header_win->GetColumnWidth(i);
      if((point.x > (m_text_x + m_width)) && (point.x <= end)) {
        flags |= wxTREE_HITTEST_ONITEMRIGHT;
        return this;
      }
      if(column >= 0 && column != theCtrl->GetMainColumn()) {
        flags |= wxTREE_HITTEST_ONITEMCOLUMN;
        return this;
      }
      return this;
    }
    if(!IsExpanded())
      return (wxTreeListItem*) NULL;
  }
  wxTreeListItem *child;
  size_t count = m_children.Count();
  for(size_t n = 0; n < count; n++) {
    child = m_children[n]->HitTest(point, theCtrl, flags, column, level + 1);
    if(child)
      return child;
  }
  return (wxTreeListItem*) NULL;
}

int wxTreeListItem::GetCurrentImage() const {
  int image = NO_IMAGE;
  if(IsExpanded()) {
    if(IsSelected())
      image = GetImage(wxTreeItemIcon_SelectedExpanded);

    else
      image = GetImage(wxTreeItemIcon_Expanded);
  } else {
    if(IsSelected())
      image = GetImage(wxTreeItemIcon_Selected);

    else
      image = GetImage(wxTreeItemIcon_Normal);
  }
  if(image == NO_IMAGE)
    image = GetImage();
  return image;
}



IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)

BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
  EVT_PAINT(wxTreeListMainWindow::OnPaint)
  EVT_ERASE_BACKGROUND(wxTreeListMainWindow::OnEraseBackground)
  EVT_MOUSE_EVENTS(wxTreeListMainWindow::OnMouse)
  EVT_CHAR(wxTreeListMainWindow::OnChar)
  EVT_SET_FOCUS(wxTreeListMainWindow::OnSetFocus)
  EVT_KILL_FOCUS(wxTreeListMainWindow::OnKillFocus)
  EVT_IDLE(wxTreeListMainWindow::OnIdle)
  EVT_SCROLLWIN(wxTreeListMainWindow::OnScroll)
  EVT_MOUSE_CAPTURE_LOST(wxTreeListMainWindow::OnCaptureLost)
END_EVENT_TABLE()





void wxTreeListMainWindow::Init() {
  m_rootItem = (wxTreeListItem*)NULL;
  m_curItem = (wxTreeListItem*)NULL;
  m_shiftItem = (wxTreeListItem*)NULL;
  m_editItem = (wxTreeListItem*)NULL;
  m_selectItem = (wxTreeListItem*)NULL;
  m_curColumn = -1;
  m_hasFocus = false;
  m_dirty = false;
  m_lineHeight = LINEHEIGHT;
  m_indent = MININDENT;
  m_linespacing = 4;
  m_hilightBrush = new wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
  m_hilightUnfocusedBrush = new wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), wxSOLID);
  m_imageListNormal = (wxImageList *) NULL;
  m_imageListButtons = (wxImageList *) NULL;
  m_imageListState = (wxImageList *) NULL;
  m_ownsImageListNormal = m_ownsImageListButtons =
                            m_ownsImageListState = false;
  m_imgWidth = 0, m_imgWidth2 = 0;
  m_imgHeight = 0, m_imgHeight2 = 0;
  m_btnWidth = 0, m_btnWidth2 = 0;
  m_btnHeight = 0, m_btnHeight2 = 0;
  m_isDragStarted = m_isDragging = false;
  m_dragItem = NULL;
  m_dragCol = -1;
  m_editTimer = new wxTreeListRenameTimer(this);
  m_editControl = NULL;
  m_lastOnSame = false;
  m_left_down_selection = false;
  m_findTimer = new wxTimer(this, -1);
  #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
  m_normalFont.MacCreateThemeFont(kThemeViewsFont);
  #else
  m_normalFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
  #endif
  m_boldFont = wxFont(m_normalFont.GetPointSize(),
                      m_normalFont.GetFamily(),
                      m_normalFont.GetStyle(),
                      wxFONTWEIGHT_BOLD,
                      m_normalFont.GetUnderlined(),
                      m_normalFont.GetFaceName(),
                      m_normalFont.GetEncoding());
  m_toolTip.clear();
  m_toolTipItem = (wxTreeListItem *) - 1;
  m_isItemToolTip = false;
}

bool wxTreeListMainWindow::Create(wxTreeListCtrl *parent,
                                  wxWindowID id,
                                  const wxPoint& pos,
                                  const wxSize& size,
                                  long style,
                                  const wxValidator &validator,
                                  const wxString& name) {
  #ifdef __WXMAC__
  style &= ~wxTR_LINES_AT_ROOT;
  style |= wxTR_NO_LINES;
  #endif
  wxScrolledWindow::Create(parent, id, pos, size, style | wxHSCROLL | wxVSCROLL, name);
  #if wxUSE_VALIDATORS
  SetValidator(validator);
  #endif
  SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX));
  SetBackgroundStyle(wxBG_STYLE_CUSTOM);
  #ifdef __WXMSW__
  {
    int i, j;
    wxBitmap bmp(8, 8);
    wxMemoryDC bdc;
    bdc.SelectObject(bmp);
    bdc.SetPen(*wxGREY_PEN);
    bdc.DrawRectangle(-1, -1, 10, 10);
    for(i = 0; i < 8; i++) {
      for(j = 0; j < 8; j++) {
        if(!((i + j) & 1))
          bdc.DrawPoint(i, j);
      }
    }
    m_dottedPen = wxPen(bmp, 1);
  }
  #else
  m_dottedPen = wxPen(_T("grey"), 0, 0);
  #endif
  m_owner = parent;
  m_main_column = 0;
  return true;
}

wxTreeListMainWindow::~wxTreeListMainWindow() {
  delete m_hilightBrush;
  delete m_hilightUnfocusedBrush;
  delete m_editTimer;
  delete m_findTimer;
  if(m_ownsImageListNormal)
    delete m_imageListNormal;
  if(m_ownsImageListState)
    delete m_imageListState;
  if(m_ownsImageListButtons)
    delete m_imageListButtons;
  if(m_editControl) {
    m_editControl->SetOwner(NULL);
    delete m_editControl;
  }
  DeleteRoot();
}




size_t wxTreeListMainWindow::GetCount() const {
  return m_rootItem == NULL ? 0 : m_rootItem->GetChildrenCount();
}

void wxTreeListMainWindow::SetIndent(unsigned int indent) {
  m_indent = wxMax((unsigned)MININDENT, indent);
  m_dirty = true;
}

void wxTreeListMainWindow::SetLineSpacing(unsigned int spacing) {
  m_linespacing = spacing;
  m_dirty = true;
  CalculateLineHeight();
}

size_t wxTreeListMainWindow::GetChildrenCount(const wxTreeItemId& item,
    bool recursively) {
  wxCHECK_MSG(item.IsOk(), 0u, _T("invalid tree item"));
  return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount(recursively);
}

void wxTreeListMainWindow::SetWindowStyle(const long styles) {
  if((styles ^ m_windowStyle) & wxTR_MULTIPLE)
    UnselectAll();
  m_windowStyle = styles;
  m_dirty = true;
}

void wxTreeListMainWindow::SetToolTip(const wxString& tip) {
  m_isItemToolTip = false;
  m_toolTip = tip;
  m_toolTipItem = (wxTreeListItem *) - 1;
}

void wxTreeListMainWindow::SetToolTip(wxToolTip *tip) {
  m_isItemToolTip = false;
  m_toolTip = (tip == NULL) ? wxString() : tip->GetTip();
  m_toolTipItem = (wxTreeListItem *) - 1;
}

void wxTreeListMainWindow::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  m_isItemToolTip = true;
  ((wxTreeListItem*) item.m_pItem)->SetToolTip(tip);
  m_toolTipItem = (wxTreeListItem *) - 1;
}




int wxTreeListMainWindow::GetItemImage(const wxTreeItemId& item, int column, wxTreeItemIcon which) const {
  wxCHECK_MSG(item.IsOk(), -1, _T("invalid tree item"));
  return ((wxTreeListItem*) item.m_pItem)->GetImage(column, which);
}

wxTreeItemData *wxTreeListMainWindow::GetItemData(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), NULL, _T("invalid tree item"));
  return ((wxTreeListItem*) item.m_pItem)->GetData();
}
wxTreeItemData *wxTreeListMainWindow::GetItemData(const wxTreeItemId& item, int column) const {
  wxCHECK_MSG(item.IsOk(), NULL, _T("invalid tree item"));
  return ((wxTreeListItem*) item.m_pItem)->GetData(column);
}

bool wxTreeListMainWindow::GetItemBold(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
  return ((wxTreeListItem *)item.m_pItem)->IsBold();
}
bool wxTreeListMainWindow::GetItemBold(const wxTreeItemId& item, int column) const {
  wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
  return ((wxTreeListItem *)item.m_pItem)->IsBold(column);
}

wxColour wxTreeListMainWindow::GetItemTextColour(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), wxNullColour, _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  wxTreeItemAttr *attr = pItem->GetAttributes();
  if(attr && attr->HasTextColour())
    return attr->GetTextColour();

  else
    return GetForegroundColour();
}
wxColour wxTreeListMainWindow::GetItemTextColour(const wxTreeItemId& item, int column) const {
  wxCHECK_MSG(item.IsOk(), wxNullColour, _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  wxTreeItemAttr *attr = pItem->GetAttributes(column);
  if(attr && attr->HasTextColour())
    return attr->GetTextColour();

  else
    return GetItemTextColour(item);
}

wxColour wxTreeListMainWindow::GetItemBackgroundColour(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), wxNullColour, _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  wxTreeItemAttr *attr = pItem->GetAttributes();
  if(attr && attr->HasBackgroundColour())
    return attr->GetBackgroundColour();

  else
    return GetBackgroundColour();
}
wxColour wxTreeListMainWindow::GetItemBackgroundColour(const wxTreeItemId& item, int column) const {
  wxCHECK_MSG(item.IsOk(), wxNullColour, _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  wxTreeItemAttr *attr = pItem->GetAttributes(column);
  if(attr && attr->HasBackgroundColour())
    return attr->GetBackgroundColour();

  else
    return GetItemBackgroundColour(item);
}

wxFont wxTreeListMainWindow::GetItemFont(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), wxNullFont, _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  wxTreeItemAttr *attr = pItem->GetAttributes();
  if(attr && attr->HasFont())
    return attr->GetFont();

  else if(pItem->IsBold())
    return m_boldFont;

  else
    return m_normalFont;
}
wxFont wxTreeListMainWindow::GetItemFont(const wxTreeItemId& item, int column) const {
  wxCHECK_MSG(item.IsOk(), wxNullFont, _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  wxTreeItemAttr *attr_cell = pItem->GetAttributes(column);
  wxTreeItemAttr *attr_row = pItem->GetAttributes();
  if(attr_cell && attr_cell->HasFont())
    return attr_cell->GetFont();

  else if(attr_row && attr_row->HasFont())
    return attr_row->GetFont();

  else if(pItem->IsBold(column))
    return m_boldFont;

  else
    return m_normalFont;
}

void wxTreeListMainWindow::SetItemHasChildren(const wxTreeItemId& item, bool has) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  pItem->SetHasPlus(has);
  RefreshLine(pItem);
}

void wxTreeListMainWindow::SetItemImage(const wxTreeItemId& item, int column, int image, wxTreeItemIcon which) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  pItem->SetImage(column, image, which);
  wxClientDC dc(this);
  CalculateSize(pItem, dc);
  RefreshLine(pItem);
}

void wxTreeListMainWindow::SetItemData(const wxTreeItemId& item,             wxTreeItemData *data) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  ((wxTreeListItem*) item.m_pItem)->SetData(data);
}

void wxTreeListMainWindow::SetItemData(const wxTreeItemId& item, int column, wxTreeItemData *data) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  ((wxTreeListItem*) item.m_pItem)->SetData(column, data);
}

void wxTreeListMainWindow::SetItemBold(const wxTreeItemId& item,             bool bold) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  if(pItem->IsBold() != bold) {
    pItem->SetBold(bold);
    RefreshLine(pItem);
  }
}

void wxTreeListMainWindow::SetItemBold(const wxTreeItemId& item, int column, bool bold) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  pItem->SetBold(column, bold);
  RefreshLine(pItem);
}

void wxTreeListMainWindow::SetItemTextColour(const wxTreeItemId& item,             const wxColour& colour) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  pItem->Attr().SetTextColour(colour);
  RefreshLine(pItem);
}

void wxTreeListMainWindow::SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  pItem->Attr(column).SetTextColour(colour);
  RefreshLine(pItem);
}

void wxTreeListMainWindow::SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  pItem->Attr().SetBackgroundColour(colour);
  RefreshLine(pItem);
}

void wxTreeListMainWindow::SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  pItem->Attr(column).SetBackgroundColour(colour);
  RefreshLine(pItem);
}

void wxTreeListMainWindow::SetItemFont(const wxTreeItemId& item,             const wxFont& font) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  pItem->Attr().SetFont(font);
  RefreshLine(pItem);
}

void wxTreeListMainWindow::SetItemFont(const wxTreeItemId& item, int column, const wxFont& font) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  pItem->Attr(column).SetFont(font);
  RefreshLine(pItem);
}


bool wxTreeListMainWindow::SetFont(const wxFont &font) {
  wxScrolledWindow::SetFont(font);
  m_normalFont = font;
  m_boldFont = wxFont(m_normalFont.GetPointSize(),
                      m_normalFont.GetFamily(),
                      m_normalFont.GetStyle(),
                      wxFONTWEIGHT_BOLD,
                      m_normalFont.GetUnderlined(),
                      m_normalFont.GetFaceName());
  CalculateLineHeight();
  return true;
}




bool wxTreeListMainWindow::IsVisible(const wxTreeItemId& item, bool fullRow, bool within) const {
  wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
  wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
  wxTreeListItem* parent = pItem->GetItemParent();
  while(parent) {
    if(parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT))
      break;
    if(!parent->IsExpanded())
      return false;
    parent = parent->GetItemParent();
  }
  if(within) {
    wxSize clientSize = GetClientSize();
    wxRect rect;
    if((!GetBoundingRect(item, rect)) ||
        ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
        (rect.GetTop() < 0 || rect.GetBottom() >= clientSize.y) ||
        (!fullRow && (rect.GetLeft() < 0 || rect.GetRight() >= clientSize.x)))
      return false;
  }
  return true;
}

bool wxTreeListMainWindow::HasChildren(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
  return ((wxTreeListItem*) item.m_pItem)->HasPlus();
}

bool wxTreeListMainWindow::IsExpanded(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
  return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
}

bool wxTreeListMainWindow::IsSelected(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
  return ((wxTreeListItem*) item.m_pItem)->IsSelected();
}

bool wxTreeListMainWindow::IsBold(const wxTreeItemId& item, int column) const {
  wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
  return ((wxTreeListItem*) item.m_pItem)->IsBold(column);
}



wxTreeItemId wxTreeListMainWindow::GetItemParent(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
}

wxTreeItemId wxTreeListMainWindow::GetFirstChild(const wxTreeItemId& item,
    wxTreeItemIdValue& cookie) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
  cookie = 0;
  return (!children.IsEmpty()) ? wxTreeItemId(children.Item(0)) : wxTreeItemId();
}

wxTreeItemId wxTreeListMainWindow::GetNextChild(const wxTreeItemId& item,
    wxTreeItemIdValue& cookie) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
  long *pIndex = ((long*)&cookie);
  return ((*pIndex) + 1 < (long)children.Count()) ? wxTreeItemId(children.Item(++(*pIndex))) : wxTreeItemId();
}

wxTreeItemId wxTreeListMainWindow::GetPrevChild(const wxTreeItemId& item,
    wxTreeItemIdValue& cookie) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
  long *pIndex = (long*)&cookie;
  return ((*pIndex) - 1 >= 0) ? wxTreeItemId(children.Item(--(*pIndex))) : wxTreeItemId();
}

wxTreeItemId wxTreeListMainWindow::GetLastChild(const wxTreeItemId& item,
    wxTreeItemIdValue& cookie) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
  long *pIndex = ((long*)&cookie);
  (*pIndex) = (long)children.Count();
  return (!children.IsEmpty()) ? wxTreeItemId(children.Last()) : wxTreeItemId();
}

wxTreeItemId wxTreeListMainWindow::GetNextSibling(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
  wxTreeListItem *parent = i->GetItemParent();
  if(!parent)
    return wxTreeItemId();
  wxArrayTreeListItems& siblings = parent->GetChildren();
  size_t index = siblings.Index(i);
  wxASSERT(index != (size_t)wxNOT_FOUND);
  return (index < siblings.Count() - 1) ? wxTreeItemId(siblings[index + 1]) : wxTreeItemId();
}

wxTreeItemId wxTreeListMainWindow::GetPrevSibling(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
  wxTreeListItem *parent = i->GetItemParent();
  if(!parent)
    return wxTreeItemId();
  wxArrayTreeListItems& siblings = parent->GetChildren();
  size_t index = siblings.Index(i);
  wxASSERT(index != (size_t)wxNOT_FOUND);
  return (index >= 1) ? wxTreeItemId(siblings[index - 1]) : wxTreeItemId();
}


wxTreeItemId wxTreeListMainWindow::GetNext(const wxTreeItemId& item, bool fulltree) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  if(fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
    wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
    if(children.GetCount() > 0)
      return children.Item(0);
  }
  wxTreeItemId next;
  wxTreeItemId parent = item;
  do {
    next = GetNextSibling(parent);
    parent = GetItemParent(parent);
  } while(!next.IsOk() && parent.IsOk());
  return next;
}


wxTreeItemId wxTreeListMainWindow::GetPrev(const wxTreeItemId& item, bool fulltree) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxTreeItemId prev = GetPrevSibling(item);
  if(! prev.IsOk())
    return GetItemParent(item);
  while(fulltree || ((wxTreeListItem*)prev.m_pItem)->IsExpanded()) {
    wxArrayTreeListItems& children = ((wxTreeListItem*)prev.m_pItem)->GetChildren();
    if(children.GetCount() == 0)
      break;
    prev = children.Item(children.GetCount() - 1);
  }
  return prev;
}

wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
  return GetNextExpanded(GetRootItem());
}

wxTreeItemId wxTreeListMainWindow::GetNextExpanded(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  return GetNext(item, false);
}

wxTreeItemId wxTreeListMainWindow::GetPrevExpanded(const wxTreeItemId& item) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  return GetPrev(item, false);
}

wxTreeItemId wxTreeListMainWindow::GetFirstVisible(bool fullRow, bool within) const {
  if(HasFlag(wxTR_HIDE_ROOT) || ! IsVisible(GetRootItem(), fullRow, within))
    return GetNextVisible(GetRootItem(), fullRow, within);

  else
    return GetRootItem();
}

wxTreeItemId wxTreeListMainWindow::GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxTreeItemId id = GetNext(item, false);
  while(id.IsOk()) {
    if(IsVisible(id, fullRow, within))
      return id;
    id = GetNext(id, false);
  }
  return wxTreeItemId();
}

wxTreeItemId wxTreeListMainWindow::GetLastVisible(bool fullRow, bool within) const {
  wxCHECK_MSG(GetRootItem().IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxTreeItemId id = GetRootItem();
  wxTreeItemId res = id;
  while((id = GetNext(id, false)).IsOk()) {
    if(IsVisible(id, fullRow, within))
      res = id;
  }
  return res;
}

wxTreeItemId wxTreeListMainWindow::GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const {
  wxCHECK_MSG(item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
  wxTreeItemId id = GetPrev(item, true);
  while(id.IsOk()) {
    if(IsVisible(id, fullRow, within))
      return id;
    id = GetPrev(id, true);
  }
  return wxTreeItemId();
}




wxTreeItemId wxTreeListMainWindow::DoInsertItem(const wxTreeItemId& parentId,
    size_t previous,
    const wxString& text,
    int image, int selImage,
    wxTreeItemData *data) {
  wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
  wxCHECK_MSG(parent, wxTreeItemId(), _T("item must have a parent, at least root!"));
  m_dirty = true;
  wxArrayString arr;
  arr.Alloc(GetColumnCount());
  for(int i = 0; i < (int)GetColumnCount(); ++i)
    arr.Add(wxEmptyString);
  arr[m_main_column] = text;
  wxTreeListItem *item = new wxTreeListItem(this, parent, arr, image, selImage, data);
  if(data != NULL)
    data->SetId(item);
  parent->Insert(item, previous);
  return item;
}

wxTreeItemId wxTreeListMainWindow::AddRoot(const wxString& text,
    int image, int selImage,
    wxTreeItemData *data) {
  wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
  wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
  m_dirty = true;
  wxArrayString arr;
  arr.Alloc(GetColumnCount());
  for(int i = 0; i < (int)GetColumnCount(); ++i)
    arr.Add(wxEmptyString);
  arr[m_main_column] = text;
  m_rootItem = new wxTreeListItem(this, (wxTreeListItem *)NULL, arr, image, selImage, data);
  if(data != NULL)
    data->SetId(m_rootItem);
  if(HasFlag(wxTR_HIDE_ROOT)) {
    m_rootItem->SetHasPlus();
    m_rootItem->Expand();
    wxTreeItemIdValue cookie = 0;
    SetCurrentItem(GetFirstChild(m_rootItem, cookie));
  }
  return m_rootItem;
}

wxTreeItemId wxTreeListMainWindow::PrependItem(const wxTreeItemId& parent,
    const wxString& text,
    int image, int selImage,
    wxTreeItemData *data) {
  return DoInsertItem(parent, 0u, text, image, selImage, data);
}

wxTreeItemId wxTreeListMainWindow::InsertItem(const wxTreeItemId& parentId,
    const wxTreeItemId& idPrevious,
    const wxString& text,
    int image, int selImage,
    wxTreeItemData *data) {
  wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
  wxCHECK_MSG(parent, wxTreeItemId(), _T("item must have a parent, at least root!"));
  int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
  wxASSERT_MSG(index != wxNOT_FOUND,
               _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling"));
  return DoInsertItem(parentId, ++index, text, image, selImage, data);
}

wxTreeItemId wxTreeListMainWindow::InsertItem(const wxTreeItemId& parentId,
    size_t before,
    const wxString& text,
    int image, int selImage,
    wxTreeItemData *data) {
  wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
  wxCHECK_MSG(parent, wxTreeItemId(), _T("item must have a parent, at least root!"));
  return DoInsertItem(parentId, before, text, image, selImage, data);
}

wxTreeItemId wxTreeListMainWindow::AppendItem(const wxTreeItemId& parentId,
    const wxString& text,
    int image, int selImage,
    wxTreeItemData *data) {
  wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
  wxCHECK_MSG(parent, wxTreeItemId(), _T("item must have a parent, at least root!"));
  return DoInsertItem(parent, parent->GetChildren().Count(), text, image, selImage, data);
}



void wxTreeListMainWindow::Delete(const wxTreeItemId& itemId) {
  if(! itemId.IsOk())
    return;
  wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
  wxTreeListItem *parent = item->GetItemParent();
  wxCHECK_RET(item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
  DoDeleteItem(item);
  if(parent)
    parent->GetChildren().Remove(item);
}


void wxTreeListMainWindow::DeleteRoot() {
  if(! m_rootItem)
    return;
  SetCurrentItem((wxTreeListItem*)NULL);
  m_selectItem = (wxTreeListItem*)NULL;
  m_shiftItem = (wxTreeListItem*)NULL;
  DeleteChildren(m_rootItem);
  SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, m_rootItem);
  delete m_rootItem;
  m_rootItem = NULL;
}


void wxTreeListMainWindow::DeleteChildren(const wxTreeItemId& itemId) {
  if(! itemId.IsOk())
    return;
  wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
  wxArrayTreeListItems& children = item->GetChildren();
  for(size_t n = children.GetCount(); n > 0; n--) {
    DoDeleteItem(children[n - 1]);
    children.RemoveAt(n - 1);
  }
}


void wxTreeListMainWindow::DoDeleteItem(wxTreeListItem *item) {
  wxCHECK_RET(item, _T("invalid item for delete!"));
  m_dirty = true;
  if(m_editControl)
    m_editControl->EndEdit(true);
  if(item == m_dragItem) {
    m_isDragStarted = m_isDragging = false;
    if(HasCapture())
      ReleaseMouse();
  }
  if(item == m_curItem) {
    SetCurrentItem(item->GetItemParent());
    if(m_curItem) {
      wxArrayTreeListItems& siblings = m_curItem->GetChildren();
      size_t index = siblings.Index(item);
      wxASSERT(index != (size_t)wxNOT_FOUND);
      SetCurrentItem(index < siblings.Count() - 1 ? siblings[index + 1] : (wxTreeListItem*)NULL);
    }
  }
  if(item == m_shiftItem)
    m_shiftItem = (wxTreeListItem*)NULL;
  if(item == m_selectItem) {
    m_selectItem = m_curItem;
    SelectItem(m_selectItem, (wxTreeItemId*)NULL, true);
  }
  wxArrayTreeListItems& children = item->GetChildren();
  for(size_t n = children.GetCount(); n > 0; n--) {
    DoDeleteItem(children[n - 1]);
    children.RemoveAt(n - 1);
  }
  SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, item);
  delete item;
}



void wxTreeListMainWindow::SetCurrentItem(const wxTreeItemId& itemId) {
  SetCurrentItem((wxTreeListItem *)(itemId ? itemId.m_pItem : NULL));
}

void wxTreeListMainWindow::SetCurrentItem(wxTreeListItem *item) {
  wxTreeListItem *old_item;
  old_item = m_curItem;
  m_curItem = item;
  if(old_item != NULL && old_item != item)
    RefreshLine(old_item);
}


void wxTreeListMainWindow::Expand(const wxTreeItemId& itemId) {
  wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
  wxCHECK_RET(item, _T("invalid item in wxTreeListMainWindow::Expand"));
  if(!item->HasPlus() || item->IsExpanded())
    return;
  wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, 0);
  event.SetInt(m_curColumn);
  if(SendEvent(0, item, &event) && !event.IsAllowed())
    return;
  item->Expand();
  m_dirty = true;
  event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
  SendEvent(0, NULL, &event);
}

void wxTreeListMainWindow::ExpandAll(const wxTreeItemId& itemId) {
  wxCHECK_RET(itemId.IsOk(), _T("invalid tree item"));
  Expand(itemId);
  if(!IsExpanded(itemId))
    return;
  wxTreeItemIdValue cookie;
  wxTreeItemId child = GetFirstChild(itemId, cookie);
  while(child.IsOk()) {
    ExpandAll(child);
    child = GetNextChild(itemId, cookie);
  }
}

void wxTreeListMainWindow::Collapse(const wxTreeItemId& itemId) {
  wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
  wxCHECK_RET(item, _T("invalid item in wxTreeListMainWindow::Collapse"));
  if(!item->HasPlus() || !item->IsExpanded())
    return;
  wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 0);
  event.SetInt(m_curColumn);
  if(SendEvent(0, item, &event) && !event.IsAllowed())
    return;
  item->Collapse();
  m_dirty = true;
  event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
  SendEvent(0, NULL, &event);
}

void wxTreeListMainWindow::CollapseAndReset(const wxTreeItemId& item) {
  wxCHECK_RET(item.IsOk(), _T("invalid tree item"));
  Collapse(item);
  DeleteChildren(item);
}

void wxTreeListMainWindow::Toggle(const wxTreeItemId& itemId) {
  wxCHECK_RET(itemId.IsOk(), _T("invalid tree item"));
  if(IsExpanded(itemId))
    Collapse(itemId);

  else
    Expand(itemId);
}

void wxTreeListMainWindow::Unselect() {
  if(m_selectItem) {
    m_selectItem->SetHilight(false);
    RefreshLine(m_selectItem);
    m_selectItem = (wxTreeListItem*)NULL;
  }
}

void wxTreeListMainWindow::UnselectAllChildren(wxTreeListItem *item) {
  wxCHECK_RET(item, _T("invalid tree item"));
  if(item->IsSelected()) {
    item->SetHilight(false);
    RefreshLine(item);
    if(item == m_selectItem)
      m_selectItem = (wxTreeListItem*)NULL;
    if(item != m_curItem)
      m_lastOnSame = false;
  }
  if(item->HasChildren()) {
    wxArrayTreeListItems& children = item->GetChildren();
    size_t count = children.Count();
    for(size_t n = 0; n < count; ++n)
      UnselectAllChildren(children[n]);
  }
}

void wxTreeListMainWindow::UnselectAll() {
  UnselectAllChildren((wxTreeListItem*)GetRootItem().m_pItem);
}



bool wxTreeListMainWindow::TagNextChildren(wxTreeListItem *crt_item,
    wxTreeListItem *last_item) {
  wxTreeListItem *parent = crt_item->GetItemParent();
  if(!parent)
    return TagAllChildrenUntilLast(crt_item, last_item);
  wxArrayTreeListItems& children = parent->GetChildren();
  int index = children.Index(crt_item);
  wxASSERT(index != wxNOT_FOUND);
  if((parent->HasChildren() && parent->IsExpanded()) ||
      ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
    size_t count = children.Count();
    for(size_t n = (index + 1); n < count; ++n) {
      if(TagAllChildrenUntilLast(children[n], last_item))
        return true;
    }
  }
  return TagNextChildren(parent, last_item);
}

bool wxTreeListMainWindow::TagAllChildrenUntilLast(wxTreeListItem *crt_item,
    wxTreeListItem *last_item) {
  crt_item->SetHilight(true);
  RefreshLine(crt_item);
  if(crt_item == last_item)
    return true;
  if(crt_item->HasChildren() && crt_item->IsExpanded()) {
    wxArrayTreeListItems& children = crt_item->GetChildren();
    size_t count = children.Count();
    for(size_t n = 0; n < count; ++n) {
      if(TagAllChildrenUntilLast(children[n], last_item))
        return true;
    }
  }
  return false;
}

bool wxTreeListMainWindow::SelectItem(const wxTreeItemId& itemId,
                                      const wxTreeItemId& lastId,
                                      bool unselect_others) {
  wxTreeListItem *item = itemId.IsOk() ? (wxTreeListItem*) itemId.m_pItem : NULL;
  wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
  event.SetInt(m_curColumn);
  event.SetOldItem(m_curItem);
  if(SendEvent(0, item, &event) && !event.IsAllowed())
    return false;
  bool bUnselectedAll = false;
  if(unselect_others) {
    if(HasFlag(wxTR_MULTIPLE)) {
      UnselectAll();
      bUnselectedAll = true;
    } else
      Unselect();
  }
  if(lastId.IsOk() && itemId.IsOk() && (itemId != lastId)) {
    if(! bUnselectedAll)
      UnselectAll();
    wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
    if(m_dirty)
      CalculatePositions();
    if(last->GetY() < item->GetY()) {
      if(!TagAllChildrenUntilLast(last, item))
        TagNextChildren(last, item);
    } else {
      if(!TagAllChildrenUntilLast(item, last))
        TagNextChildren(item, last);
    }
  } else if(itemId.IsOk()) {
    item->SetHilight(!item->IsSelected());
    RefreshLine(item);
    if(unselect_others)
      m_selectItem = (item->IsSelected()) ? item : (wxTreeListItem*)NULL;
  } else {
    if(! bUnselectedAll)
      UnselectAll();
  }
  event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
  SendEvent(0, NULL, &event);
  return true;
}

void wxTreeListMainWindow::SelectAll() {
  wxTreeItemId root = GetRootItem();
  wxCHECK_RET(HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
  wxCHECK_RET(root.IsOk(), _T("no tree"));
  wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
  event.SetOldItem(m_curItem);
  event.SetInt(-1);
  if(SendEvent(0, m_rootItem, &event) && !event.IsAllowed())
    return;
  wxTreeItemIdValue cookie = 0;
  wxTreeListItem *first = (wxTreeListItem *)GetFirstChild(root, cookie).m_pItem;
  wxTreeListItem *last = (wxTreeListItem *)GetLastChild(root, cookie).m_pItem;
  if(!TagAllChildrenUntilLast(first, last))
    TagNextChildren(first, last);
  event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
  SendEvent(0, NULL, &event);
}

void wxTreeListMainWindow::FillArray(wxTreeListItem *item,
                                     wxArrayTreeItemIds &array) const {
  if(item->IsSelected())
    array.Add(wxTreeItemId(item));
  if(item->HasChildren()) {
    wxArrayTreeListItems& children = item->GetChildren();
    size_t count = children.GetCount();
    for(size_t n = 0; n < count; ++n)
      FillArray(children[n], array);
  }
}

size_t wxTreeListMainWindow::GetSelections(wxArrayTreeItemIds &array) const {
  array.Empty();
  wxTreeItemId idRoot = GetRootItem();
  if(idRoot.IsOk())
    FillArray((wxTreeListItem*) idRoot.m_pItem, array);
  return array.Count();
}

void wxTreeListMainWindow::EnsureVisible(const wxTreeItemId& item) {
  if(!item.IsOk())
    return;
  wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
  wxTreeListItem *parent = gitem->GetItemParent();
  while(parent) {
    Expand(parent);
    parent = parent->GetItemParent();
  }
  ScrollTo(item);
  RefreshLine(gitem);
}

void wxTreeListMainWindow::ScrollTo(const wxTreeItemId &item) {
  if(!item.IsOk())
    return;
  if(m_dirty)
    CalculatePositions();
  wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
  int item_y = gitem->GetY();
  int xUnit, yUnit;
  GetScrollPixelsPerUnit(&xUnit, &yUnit);
  int start_x = 0;
  int start_y = 0;
  GetViewStart(&start_x, &start_y);
  start_y *= yUnit;
  int client_h = 0;
  int client_w = 0;
  GetClientSize(&client_w, &client_h);
  int x = 0;
  int y = 0;
  m_rootItem->GetSize(x, y, this);
  x = m_owner->GetHeaderWindow()->GetWidth();
  y += yUnit + 2;
  int x_pos = GetScrollPos(wxHORIZONTAL);
  if(item_y < start_y + 3)
    SetScrollbars(xUnit, yUnit, xUnit ? x / xUnit : 0, yUnit ? y / yUnit : 0, x_pos, yUnit ? item_y / yUnit : 0);

  else if(item_y + GetLineHeight(gitem) > start_y + client_h) {
    item_y += yUnit + 2;
    SetScrollbars(xUnit, yUnit, xUnit ? x / xUnit : 0, yUnit ? y / yUnit : 0, x_pos, yUnit ? (item_y + GetLineHeight(gitem) - client_h) / yUnit : 0);
  }
}

static wxTreeListMainWindow *s_treeBeingSorted = NULL;

static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1, wxTreeListItem **item2) {
  wxCHECK_MSG(s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()"));
  return s_treeBeingSorted->OnCompareItems(*item1, *item2);
}

int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2) {
  return (m_sortColumn == -1
          ? m_owner->OnCompareItems(item1, item2)
          : (m_ReverseSortOrder
             ? m_owner->OnCompareItems(item2, item1, m_sortColumn)
             : m_owner->OnCompareItems(item1, item2, m_sortColumn)
            )
         );
}

void wxTreeListMainWindow::SortChildren(const wxTreeItemId& itemId, int column, bool reverseOrder) {
  wxCHECK_RET(itemId.IsOk(), _T("invalid tree item"));
  wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
  wxCHECK_RET(!s_treeBeingSorted,
              _T("wxTreeListMainWindow::SortChildren is not reentrant"));
  wxArrayTreeListItems& children = item->GetChildren();
  if(children.Count() > 1) {
    m_dirty = true;
    s_treeBeingSorted = this;
    m_sortColumn = column;
    m_ReverseSortOrder = reverseOrder;
    children.Sort(tree_ctrl_compare_func);
    s_treeBeingSorted = NULL;
  }
}

wxTreeItemId wxTreeListMainWindow::FindItem(const wxTreeItemId& item, int column, const wxString& str, int mode) {
  wxString itemText;
  wxTreeItemId next = item;
  if(next.IsOk()) {
    if(mode & wxTL_MODE_NAV_LEVEL)
      next = GetNextSibling(next);

    else if(mode & wxTL_MODE_NAV_VISIBLE)
      next = GetNextVisible(next, false, true);

    else if(mode & wxTL_MODE_NAV_EXPANDED)
      next = GetNextExpanded(next);

    else
      next = GetNext(next, true);
  }
  wxTreeItemIdValue cookie = 0;
  if(!next.IsOk()) {
    next = GetRootItem();
    if(next.IsOk() && HasFlag(wxTR_HIDE_ROOT))
      next = GetFirstChild(GetRootItem(), cookie);
  }
  if(!next.IsOk())
    return (wxTreeItemId*)NULL;
  while(next.IsOk() && (next != item)) {
    if(mode & wxTL_MODE_FIND_PARTIAL)
      itemText = GetItemText(next, column).Mid(0, str.Length());

    else
      itemText = GetItemText(next, column);
    if(mode & wxTL_MODE_FIND_NOCASE) {
      if(itemText.CmpNoCase(str) == 0)
        return next;
    } else {
      if(itemText.Cmp(str) == 0)
        return next;
    }
    if(mode & wxTL_MODE_NAV_LEVEL)
      next = GetNextSibling(next);

    else if(mode & wxTL_MODE_NAV_VISIBLE)
      next = GetNextVisible(next, false, true);

    else if(mode & wxTL_MODE_NAV_EXPANDED)
      next = GetNextExpanded(next);

    else
      next = GetNext(next, true);
    if(!next.IsOk() && item.IsOk()) {
      next = (wxTreeListItem*)GetRootItem().m_pItem;
      if(HasFlag(wxTR_HIDE_ROOT))
        next = (wxTreeListItem*)GetNextChild(GetRootItem().m_pItem, cookie).m_pItem;
    }
  }
  return (wxTreeItemId*)NULL;
}

void wxTreeListMainWindow::SetDragItem(const wxTreeItemId& item) {
  wxTreeListItem *prevItem = m_dragItem;
  m_dragItem = (wxTreeListItem*) item.m_pItem;
  if(prevItem)
    RefreshLine(prevItem);
  if(m_dragItem)
    RefreshLine(m_dragItem);
}

void wxTreeListMainWindow::CalculateLineHeight() {
  wxClientDC dc(this);
  dc.SetFont(m_normalFont);
  m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
  if(m_imageListNormal) {
    int n = m_imageListNormal->GetImageCount();
    for(int i = 0; i < n ; i++) {
      int width = 0, height = 0;
      m_imageListNormal->GetSize(i, width, height);
      if(height > m_lineHeight)
        m_lineHeight = height + m_linespacing;
    }
  }
  if(m_imageListButtons) {
    int n = m_imageListButtons->GetImageCount();
    for(int i = 0; i < n ; i++) {
      int width = 0, height = 0;
      m_imageListButtons->GetSize(i, width, height);
      if(height > m_lineHeight)
        m_lineHeight = height + m_linespacing;
    }
  }
  if(m_lineHeight < 30)
    m_lineHeight += 2;

  else
    m_lineHeight += m_lineHeight / 10;
}

void wxTreeListMainWindow::SetImageList(wxImageList *imageList) {
  if(m_ownsImageListNormal)
    delete m_imageListNormal;
  m_imageListNormal = imageList;
  m_ownsImageListNormal = false;
  m_dirty = true;
  CalculateLineHeight();
}

void wxTreeListMainWindow::SetStateImageList(wxImageList *imageList) {
  if(m_ownsImageListState)
    delete m_imageListState;
  m_imageListState = imageList;
  m_ownsImageListState = false;
}

void wxTreeListMainWindow::SetButtonsImageList(wxImageList *imageList) {
  if(m_ownsImageListButtons)
    delete m_imageListButtons;
  m_imageListButtons = imageList;
  m_ownsImageListButtons = false;
  m_dirty = true;
  CalculateLineHeight();
}

void wxTreeListMainWindow::AssignImageList(wxImageList *imageList) {
  SetImageList(imageList);
  m_ownsImageListNormal = true;
}

void wxTreeListMainWindow::AssignStateImageList(wxImageList *imageList) {
  SetStateImageList(imageList);
  m_ownsImageListState = true;
}

void wxTreeListMainWindow::AssignButtonsImageList(wxImageList *imageList) {
  SetButtonsImageList(imageList);
  m_ownsImageListButtons = true;
}

void wxTreeListMainWindow::AdjustMyScrollbars() {
  if(m_rootItem) {
    int xUnit, yUnit;
    GetScrollPixelsPerUnit(&xUnit, &yUnit);
    if(xUnit == 0)
      xUnit = GetCharWidth();
    if(yUnit == 0)
      yUnit = m_lineHeight;
    int x = 0, y = 0;
    m_rootItem->GetSize(x, y, this);
    y += yUnit + 2;
    int x_pos = GetScrollPos(wxHORIZONTAL);
    int y_pos = GetScrollPos(wxVERTICAL);
    x = m_owner->GetHeaderWindow()->GetWidth() + 2;
    if(x < GetClientSize().GetWidth())
      x_pos = 0;
    SetScrollbars(xUnit, yUnit, x / xUnit, y / yUnit, x_pos, y_pos);
  } else
    SetScrollbars(0, 0, 0, 0);
}

int wxTreeListMainWindow::GetLineHeight(wxTreeListItem *item) const {
  if(GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT)
    return item->GetHeight();

  else
    return m_lineHeight;
}

void wxTreeListMainWindow::PaintItem(wxTreeListItem *item, wxDC& dc) {
  wxColour colText = GetItemTextColour(item);
  wxColour colBg = GetItemBackgroundColour(item);
  wxColour colTextHilight = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
  int total_w = m_owner->GetHeaderWindow()->GetWidth();
  int total_h = GetLineHeight(item);
  int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
  int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0;
  wxDCClipper clipper(dc, 0, item->GetY(), total_w, total_h);
  int text_h = 0;
  dc.GetTextExtent(item->GetText(GetMainColumn()).size() > 0
                   ? item->GetText(GetMainColumn())
                   : _T("M"),
                   NULL, &text_h);
  dc.SetBrush(wxBrush(colBg, wxSOLID));
  dc.SetPen(*wxTRANSPARENT_PEN);
  if(HasFlag(wxTR_FULL_ROW_HIGHLIGHT)) {
    if(item->IsSelected()) {
      if(! m_isDragging && m_hasFocus) {
        dc.SetBrush(*m_hilightBrush);
        #ifndef __WXMAC__
        dc.SetPen(*wxBLACK_PEN);
        #endif
      } else {
        dc.SetBrush(*m_hilightUnfocusedBrush);
        #ifndef __WXMAC__
        dc.SetPen(*wxTRANSPARENT_PEN);
        #endif
      }
      dc.SetTextForeground(colTextHilight);
    } else {
      dc.SetTextForeground(GetItemTextColour(item));
      if(item == m_curItem)
        dc.SetPen(m_hasFocus ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
    }
    dc.DrawRectangle(0, item->GetY() + off_h, total_w, total_h - off_h);
  }
  int text_extraH = (total_h > text_h) ? (total_h - text_h) / 2 : 0;
  int img_extraH = (total_h > m_imgHeight) ? (total_h - m_imgHeight) / 2 : 0;
  int x_colstart = 0;
  for(int i = 0; i < GetColumnCount(); ++i) {
    if(!m_owner->GetHeaderWindow()->IsColumnShown(i))
      continue;
    int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
    if(col_w <= 0)
      continue;
    wxDCClipper clipper(dc, x_colstart, item->GetY(), col_w, total_h);
    dc.SetFont(GetItemFont(item, i));
    colText = GetItemTextColour(item, i);
    colBg = GetItemBackgroundColour(item, i);
    int x = 0;
    int image = NO_IMAGE;
    int image_w = 0;
    if(i == GetMainColumn()) {
      x = item->GetX() + MARGIN;
      if(HasButtons())
        x += (m_btnWidth - m_btnWidth2) + LINEATROOT;

      else
        x -= m_indent / 2;
      if(m_imageListNormal)
        image = item->GetCurrentImage();
    } else {
      x = x_colstart + MARGIN;
      image = item->GetImage(i);
    }
    if(image != NO_IMAGE)
      image_w = m_imgWidth + MARGIN;
    int w = 0, text_w = 0;
    wxString text = item->GetText(i);
    dc.GetTextExtent(text, &text_w, NULL);
    switch(m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment()) {
      case wxALIGN_LEFT:
        break;
      case wxALIGN_RIGHT:
        w = col_w - (image_w + text_w + off_w + MARGIN);
        x += (w > 0) ? w : 0;
        break;
      case wxALIGN_CENTER:
        w = (col_w - (image_w + text_w + off_w + MARGIN)) / 2;
        x += (w > 0) ? w : 0;
        break;
    }
    int text_x = x + image_w;
    if(i == GetMainColumn())
      item->SetTextX(text_x);
    if(! HasFlag(wxTR_FULL_ROW_HIGHLIGHT)) {
      bool drawCursor = false;
      #ifndef __WXMAC__
      drawCursor = (item == m_curItem && i == m_curColumn && !m_isDragging && m_hasFocus);
      #endif
      if(item->IsSelected() && i == GetMainColumn()) {
        dc.SetPen(*wxTRANSPARENT_PEN);
        dc.SetBrush(wxBrush(colBg, wxSOLID));
        dc.DrawRectangle(x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
        dc.SetPen(drawCursor ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
        dc.SetBrush(!m_isDragging && m_hasFocus ? *m_hilightBrush : *m_hilightUnfocusedBrush);
        dc.SetTextForeground(colTextHilight);
        dc.DrawRectangle(text_x, item->GetY() + off_h, text_w, total_h - off_h);
      } else {
        dc.SetPen(drawCursor && i != GetMainColumn() ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
        dc.SetBrush(wxBrush(colBg, wxSOLID));
        dc.SetTextForeground(colText);
        dc.DrawRectangle(x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
        if(drawCursor && i == GetMainColumn()) {
          dc.SetPen(*wxBLACK_PEN);
          dc.SetBackgroundMode(wxTRANSPARENT);
          dc.DrawRectangle(text_x, item->GetY() + off_h, text_w, total_h - off_h);
        }
      }
    }
    if(HasFlag(wxTR_COLUMN_LINES)) {
      wxPen pen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT), 1, wxSOLID);
      dc.SetPen((GetBackgroundColour() == *wxWHITE) ? pen : *wxWHITE_PEN);
      dc.DrawLine(x_colstart + col_w - 1, item->GetY(), x_colstart + col_w - 1, item->GetY() + total_h);
    }
    dc.SetBackgroundMode(wxTRANSPARENT);
    if(image != NO_IMAGE && m_imageListNormal && image < m_imageListNormal->GetImageCount()) {
      int y = item->GetY() + img_extraH;
      m_imageListNormal->Draw(image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT);
    }
    int text_y = item->GetY() + text_extraH;
    dc.DrawText(text, (wxCoord)text_x, (wxCoord)text_y);
    x_colstart += col_w;
  }
  dc.SetFont(m_normalFont);
}

void wxTreeListMainWindow::PaintLevel(wxTreeListItem *item, wxDC &dc,
                                      int level, int &y, int x_maincol) {
  if(HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
    wxArrayTreeListItems& children = item->GetChildren();
    for(size_t n = 0; n < children.Count(); n++)
      PaintLevel(children[n], dc, 1, y, x_maincol);
    return;
  }
  int x = x_maincol + MARGIN;
  if(HasFlag(wxTR_LINES_AT_ROOT))
    x += LINEATROOT;
  if(HasButtons())
    x += (m_btnWidth - m_btnWidth2);

  else
    x += (m_indent - m_indent / 2);
  if(HasFlag(wxTR_HIDE_ROOT))
    x += m_indent * (level - 1);

  else
    x += m_indent * level;
  item->SetX(x);
  item->SetY(y);
  int h = GetLineHeight(item);
  int y_top = y;
  int y_mid = y_top + (h / 2);
  y += h;
  int exposed_x = dc.LogicalToDeviceX(0);
  int exposed_y = dc.LogicalToDeviceY(y_top);
  if(IsExposed(exposed_x, exposed_y, 10000, h)) {
    if(HasFlag(wxTR_ROW_LINES)) {
      int total_width = m_owner->GetHeaderWindow()->GetWidth();
      wxPen pen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT), 1, wxSOLID);
      dc.SetPen((GetBackgroundColour() == *wxWHITE) ? pen : *wxWHITE_PEN);
      dc.DrawLine(0, y_top, total_width, y_top);
      dc.DrawLine(0, y_top + h, total_width, y_top + h);
    }
    PaintItem(item, dc);
    dc.SetBrush(*wxWHITE_BRUSH);
    dc.SetPen(m_dottedPen);
    int clip_width = m_owner->GetHeaderWindow()->
                     GetColumn(m_main_column).GetWidth();
    wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
    if(!HasFlag(wxTR_NO_LINES)) {
      dc.SetPen(m_dottedPen);
      int x2 = x - m_indent;
      if(x2 < (x_maincol + MARGIN))
        x2 = x_maincol + MARGIN;
      int x3 = x + (m_btnWidth - m_btnWidth2);
      if(HasButtons()) {
        if(item->HasPlus()) {
          dc.DrawLine(x2, y_mid, x - m_btnWidth2, y_mid);
          dc.DrawLine(x3, y_mid, x3 + LINEATROOT, y_mid);
        } else
          dc.DrawLine(x2, y_mid, x3 + LINEATROOT, y_mid);
      } else
        dc.DrawLine(x2, y_mid, x - m_indent / 2, y_mid);
    }
    if(item->HasPlus() && HasButtons()) {
      if(m_imageListButtons) {
        int image = wxTreeItemIcon_Normal;
        if(item->IsExpanded())
          image = wxTreeItemIcon_Expanded;
        if(item->IsSelected())
          image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
        int xx = x - m_btnWidth2 + MARGIN;
        int yy = y_mid - m_btnHeight2;
        dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
        m_imageListButtons->Draw(image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
        dc.DestroyClippingRegion();
      } else if(HasFlag(wxTR_TWIST_BUTTONS)) {
        dc.SetPen(*wxBLACK_PEN);
        dc.SetBrush(*m_hilightBrush);
        wxPoint button[3];
        if(item->IsExpanded()) {
          button[0].x = x - (m_btnWidth2 + 1);
          button[0].y = y_mid - (m_btnHeight / 3);
          button[1].x = x + (m_btnWidth2 + 1);
          button[1].y = button[0].y;
          button[2].x = x;
          button[2].y = button[0].y + (m_btnHeight2 + 1);
        } else {
          button[0].x = x - (m_btnWidth / 3);
          button[0].y = y_mid - (m_btnHeight2 + 1);
          button[1].x = button[0].x;
          button[1].y = y_mid + (m_btnHeight2 + 1);
          button[2].x = button[0].x + (m_btnWidth2 + 1);
          button[2].y = y_mid;
        }
        dc.DrawPolygon(3, button);
      } else {
        wxRect rect(x - m_btnWidth2, y_mid - m_btnHeight2, m_btnWidth, m_btnHeight);
        int flag = item->IsExpanded() ? wxCONTROL_EXPANDED : 0;
        wxRendererNative::GetDefault().DrawTreeItemButton(this, dc, rect, flag);
      }
    }
  }
  dc.SetBrush(*wxWHITE_BRUSH);
  dc.SetPen(m_dottedPen);
  dc.SetTextForeground(*wxBLACK);
  if(item->IsExpanded()) {
    wxArrayTreeListItems& children = item->GetChildren();
    int clip_width = m_owner->GetHeaderWindow()->
                     GetColumn(m_main_column).GetWidth();
    int oldY;
    if(m_imgWidth > 0)
      oldY = y_mid + m_imgHeight2;

    else
      oldY = y_mid + h / 2;
    int y2;
    for(size_t n = 0; n < children.Count(); ++n) {
      y2 = y + h / 2;
      PaintLevel(children[n], dc, level + 1, y, x_maincol);
      wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
      if(!HasFlag(wxTR_NO_LINES)) {
        x = item->GetX();
        dc.DrawLine(x, oldY, x, y2);
        oldY = y2;
      }
    }
  }
}


void wxTreeListMainWindow::OnPaint(wxPaintEvent &WXUNUSED(event)) {
  wxAutoBufferedPaintDC dc(this);
  wxBrush brush(GetBackgroundColour(), wxSOLID);
  dc.SetBackground(brush);
  dc.Clear();
  DoPrepareDC(dc);
  if(!m_rootItem || (GetColumnCount() <= 0))
    return;
  if(m_imageListButtons)
    m_imageListButtons->GetSize(0, m_btnWidth, m_btnHeight);

  else if(HasButtons()) {
    m_btnWidth = BTNWIDTH;
    m_btnHeight = BTNHEIGHT;
  }
  m_btnWidth2 = m_btnWidth / 2;
  m_btnHeight2 = m_btnHeight / 2;
  if(m_imageListNormal)
    m_imageListNormal->GetSize(0, m_imgWidth, m_imgHeight);
  m_imgWidth2 = m_imgWidth / 2;
  m_imgHeight2 = m_imgHeight / 2;
  if(m_imageListButtons)
    m_indent = wxMax(MININDENT, m_btnWidth + MARGIN);

  else if(HasButtons())
    m_indent = wxMax(MININDENT, m_btnWidth + LINEATROOT);
  dc.SetFont(m_normalFont);
  dc.SetPen(m_dottedPen);
  int x_maincol = 0;
  int i = 0;
  for(i = 0; i < (int)GetMainColumn(); ++i) {
    if(!m_owner->GetHeaderWindow()->IsColumnShown(i))
      continue;
    x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth(i);
  }
  int y = 0;
  PaintLevel(m_rootItem, dc, 0, y, x_maincol);
}

void wxTreeListMainWindow::OnSetFocus(wxFocusEvent &event) {
  m_hasFocus = true;
  RefreshSelected();
  if(m_curItem)
    RefreshLine(m_curItem);
  event.Skip();
}

void wxTreeListMainWindow::OnKillFocus(wxFocusEvent &event) {
  m_hasFocus = false;
  RefreshSelected();
  if(m_curItem)
    RefreshLine(m_curItem);
  event.Skip();
}

void wxTreeListMainWindow::OnChar(wxKeyEvent &event) {
  wxTreeEvent nevent(wxEVT_COMMAND_TREE_KEY_DOWN, 0);
  nevent.SetInt(m_curColumn);
  nevent.SetKeyEvent(event);
  if(SendEvent(0, NULL, &nevent))
    return;
  bool curItemSet = false;
  if(!m_curItem) {
    if(! GetRootItem().IsOk())
      return;
    SetCurrentItem((wxTreeListItem*)GetRootItem().m_pItem);
    if(HasFlag(wxTR_HIDE_ROOT)) {
      wxTreeItemIdValue cookie = 0;
      SetCurrentItem((wxTreeListItem*)GetFirstChild(m_curItem, cookie).m_pItem);
    }
    SelectItem(m_curItem, (wxTreeItemId*)NULL, true);
    curItemSet = true;
  }
  if(HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
    if(!m_shiftItem)
      m_shiftItem = m_curItem;
  } else
    m_shiftItem = (wxTreeListItem*)NULL;
  if(curItemSet)
    return;
  wxTreeItemId newItem = (wxTreeItemId*)NULL;
  switch(event.GetKeyCode()) {
    case '+':
    case WXK_ADD: {
      if(m_curItem->HasPlus() && !IsExpanded(m_curItem))
        Expand(m_curItem);
    }
    break;
    case '-':
    case WXK_SUBTRACT: {
      if(m_curItem->HasPlus() && IsExpanded(m_curItem))
        Collapse(m_curItem);
    }
    break;
    case '*':
    case WXK_MULTIPLY: {
      if(m_curItem->HasPlus() && !IsExpanded(m_curItem))
        ExpandAll(m_curItem);

      else if(m_curItem->HasPlus())
        Collapse(m_curItem);
    }
    break;
    case ' ': {
      SelectItem(m_curItem, (wxTreeListItem*)NULL, false);
    }
    break;
    case WXK_RETURN: {
      if(! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_curItem)) {
        if(m_curItem && m_curItem->HasPlus())
          Toggle(m_curItem);
      }
    }
    break;
    case WXK_BACK: {
      newItem = GetItemParent(m_curItem);
      if((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT))
        newItem = GetPrevSibling(m_curItem);
    }
    break;
    case WXK_HOME: {
      newItem = GetFirstVisible(false, false);
    }
    break;
    case WXK_PAGEUP: {
      int flags = 0;
      int col = 0;
      wxPoint abs_p = CalcUnscrolledPosition(wxPoint(1, 1));
      newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
      newItem = GetFirstVisible(false, true);
      if(newItem == m_curItem) {
        abs_p.y -= GetClientSize().GetHeight() - m_curItem->GetHeight();
        if(abs_p.y < 0)
          abs_p.y = 0;
        newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
      }
    }
    break;
    case WXK_UP: {
      newItem = GetPrevSibling(m_curItem);
      if(newItem) {
        wxTreeItemIdValue cookie = 0;
        while(IsExpanded(newItem) && HasChildren(newItem))
          newItem = GetLastChild(newItem, cookie);
      } else {
        newItem = GetItemParent(m_curItem);
        if((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT))
          newItem = (wxTreeItemId*)NULL;
      }
    }
    break;
    case WXK_LEFT: {
      if(IsExpanded(m_curItem))
        Collapse(m_curItem);

      else {
        newItem = GetItemParent(m_curItem);
        if((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT))
          newItem = GetPrevSibling(m_curItem);
      }
    }
    break;
    case WXK_RIGHT: {
      if(m_curItem->HasPlus() && !IsExpanded(m_curItem))
        Expand(m_curItem);

      else {
        if(IsExpanded(m_curItem) && HasChildren(m_curItem)) {
          wxTreeItemIdValue cookie = 0;
          newItem = GetFirstChild(m_curItem, cookie);
        }
      }
    }
    break;
    case WXK_DOWN: {
      if(IsExpanded(m_curItem) && HasChildren(m_curItem)) {
        wxTreeItemIdValue cookie = 0;
        newItem = GetFirstChild(m_curItem, cookie);
      }
      if(!newItem) {
        wxTreeItemId parent = m_curItem;
        do {
          newItem = GetNextSibling(parent);
          parent = GetItemParent(parent);
        } while(!newItem && parent);
      }
    }
    break;
    case WXK_PAGEDOWN: {
      int flags = 0;
      int col = 0;
      wxPoint abs_p = CalcUnscrolledPosition(wxPoint(1, GetClientSize().GetHeight() - m_curItem->GetHeight()));
      newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
      newItem = GetLastVisible(false, true);
      if(newItem == m_curItem) {
        abs_p.y += GetClientSize().GetHeight() - m_curItem->GetHeight();
        newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
      }
      if(! newItem)
        newItem = GetLastVisible(false, false);
    }
    break;
    case WXK_END: {
      newItem = GetLastVisible(false, false);
    }
    break;
    default:
      if(event.GetKeyCode() >= (int)' ') {
        if(!m_findTimer->IsRunning())
          m_findStr.Clear();
        m_findStr << event.GetKeyCode();
        m_findTimer->Start(FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
        wxTreeItemId prev = m_curItem ? (wxTreeItemId*)m_curItem : (wxTreeItemId*)NULL;
        while(true) {
          newItem = FindItem(prev, GetCurrentColumn(), m_findStr, wxTL_MODE_NAV_EXPANDED | wxTL_MODE_FIND_PARTIAL | wxTL_MODE_FIND_NOCASE);
          if(newItem || (m_findStr.Length() <= 1))
            break;
          m_findStr.RemoveLast();
        };
      }
      event.Skip();
  }
  if(newItem) {
    if(!event.ControlDown()) {
      bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
                               HasFlag(wxTR_MULTIPLE));
      SelectItem(newItem, m_shiftItem, unselect_others);
    }
    EnsureVisible(newItem);
    wxTreeListItem *oldItem = m_curItem;
    SetCurrentItem((wxTreeListItem*)newItem.m_pItem);
    RefreshLine(oldItem);
  }
}

wxTreeItemId wxTreeListMainWindow::HitTest(const wxPoint& point, int& flags, int& column) {
  int w, h;
  GetSize(&w, &h);
  flags = 0;
  column = -1;
  if(point.x < 0)
    flags |= wxTREE_HITTEST_TOLEFT;
  if(point.x > w)
    flags |= wxTREE_HITTEST_TORIGHT;
  if(point.y < 0)
    flags |= wxTREE_HITTEST_ABOVE;
  if(point.y > h)
    flags |= wxTREE_HITTEST_BELOW;
  if(flags)
    return wxTreeItemId();
  if(!m_rootItem) {
    flags = wxTREE_HITTEST_NOWHERE;
    column = -1;
    return wxTreeItemId();
  }
  wxTreeListItem *hit = m_rootItem->HitTest(CalcUnscrolledPosition(point),
                        this, flags, column, 0);
  if(!hit) {
    flags = wxTREE_HITTEST_NOWHERE;
    column = -1;
    return wxTreeItemId();
  }
  return hit;
}

bool wxTreeListMainWindow::GetBoundingRect(const wxTreeItemId& itemId, wxRect& rect,
    bool WXUNUSED(textOnly)) const {
  wxCHECK_MSG(itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect"));
  wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
  int xUnit, yUnit;
  GetScrollPixelsPerUnit(&xUnit, &yUnit);
  int startX, startY;
  GetViewStart(& startX, & startY);
  rect.x = item->GetX() - startX * xUnit;
  rect.y = item->GetY() - startY * yUnit;
  rect.width = item->GetWidth();
  rect.height = GetLineHeight(item);
  return true;
}



void wxTreeListMainWindow::EditLabel(const wxTreeItemId& item, int column) {
  if(!item.IsOk())
    return;
  if(!((column >= 0) && (column < GetColumnCount())))
    return;
  if(m_editControl)
    m_editControl->EndEdit(true);
  m_editItem = (wxTreeListItem*) item.m_pItem;
  wxTreeEvent te(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 0);
  te.SetInt(column);
  SendEvent(0, m_editItem, &te);
  if(!te.IsAllowed())
    return;
  if(m_dirty)
    CalculatePositions();
  wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
  int x = 0;
  int w = +4;
  int y = m_editItem->GetY() + 1;
  int h = m_editItem->GetHeight() - 1;
  long style = 0;
  if(column == GetMainColumn()) {
    x += m_editItem->GetTextX() - 2;
    w += m_editItem->GetWidth();
  } else {
    for(int i = 0; i < column; ++i) {
      if(header_win->IsColumnShown(i))
        x += header_win->GetColumnWidth(i);
    }
    w += header_win->GetColumnWidth(column);
  }
  switch(header_win->GetColumnAlignment(column)) {
    case wxALIGN_LEFT:
    {style = wxTE_LEFT;   x -= 1; break;}
    case wxALIGN_CENTER:
    {style = wxTE_CENTER; x -= 1; break;}
    case wxALIGN_RIGHT:
    {style = wxTE_RIGHT;  x += 0; break;}
  }
  y -= 2;
  x -= 2;
  w += 4;
  h += 4;
  wxClientDC dc(this);
  PrepareDC(dc);
  x = dc.LogicalToDeviceX(x);
  y = dc.LogicalToDeviceY(y);
  m_editCol = column;
  m_editControl = new wxEditTextCtrl(this, -1, &m_editAccept, &m_editRes,
                                     this, m_editItem->GetText(column),
                                     wxPoint(x, y), wxSize(w, h), style);
  m_editControl->SetFocus();
}

void wxTreeListMainWindow::OnRenameTimer() {
  EditLabel(m_curItem, GetCurrentColumn());
}

void wxTreeListMainWindow::OnRenameAccept(bool isCancelled) {
  wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, 0);
  le.SetLabel(m_editRes);
  le.SetEditCanceled(isCancelled);
  le.SetInt(m_editCol);
  SendEvent(0, m_editItem, &le);
  if(! isCancelled  && le.IsAllowed())
    SetItemText(m_editItem, le.GetInt(), le.GetLabel());
}

void wxTreeListMainWindow::EndEdit(bool isCancelled) {
  if(m_editControl)
    m_editControl->EndEdit(true);
}

void wxTreeListMainWindow::OnMouse(wxMouseEvent &event) {
  bool mayDrag = true;
  bool maySelect = true;
  bool mayClick = true;
  bool mayDoubleClick = true;
  bool bSkip = true;
  if(m_owner->GetEventHandler()->ProcessEvent(event))
    return;
  if(!m_rootItem)
    return;
  wxPoint p = wxPoint(event.GetX(), event.GetY());
  int flags = 0;
  wxTreeListItem *item = m_rootItem->HitTest(CalcUnscrolledPosition(p),
                         this, flags, m_curColumn, 0);
  bool bCrosshair = (item && item->HasPlus() && (flags & wxTREE_HITTEST_ONITEMBUTTON));
  if(m_isDragging)
    maySelect = mayDoubleClick = false;
  if(event.Dragging())
    maySelect = mayDoubleClick = mayClick = false;
  if(bCrosshair) {
    if(event.LeftDown())
      maySelect = false;
    mayDoubleClick = false;
  }
  if(mayDoubleClick)
    mayDoubleClick = mayClick;
  if(maySelect)
    maySelect = mayClick;
  if(maySelect) {
    if(HasFlag(wxTR_MULTIPLE)) {
      if(event.ControlDown() || event.ShiftDown()) {
        maySelect = maySelect && (event.LeftDown() || event.RightDown());
        m_lastOnSame = false;
      } else if((item != NULL && item->IsSelected()))
        maySelect = maySelect && event.LeftUp();

      else
        maySelect = maySelect && (event.LeftDown() || event.RightDown());
    } else
      maySelect = maySelect && (event.LeftDown() || event.RightDown());
  }
  if(event.LeftDown() || event.MiddleDown() || event.RightDown())
    SetFocus();
  if(item != m_toolTipItem) {
    if(item == NULL) {
      m_toolTipItem = NULL;
      wxScrolledWindow::SetToolTip(m_toolTip);
    } else {
      const wxString *tip = item->GetToolTip();
      if(tip) {
        m_toolTipItem = item;
        wxScrolledWindow::SetToolTip(*tip);
      } else if(m_isItemToolTip) {
        m_toolTipItem = item;
        wxScrolledWindow::SetToolTip(wxString());
      } else if(m_toolTipItem != NULL) {
        m_toolTipItem = NULL;
        wxScrolledWindow::SetToolTip(m_toolTip);
      }
    }
  }
  if(mayClick) {
    if(event.LeftDown())
      m_lastOnSame = (item == m_curItem);
    if(bCrosshair && event.LeftDown()) {
      bSkip = false;
      Toggle(item);
    }
    if(maySelect) {
      bSkip = false;
      if(event.LeftDown() && HasFlag(wxTR_MULTIPLE) && event.ShiftDown())  {
        if(!m_shiftItem)
          m_shiftItem = m_curItem;
      } else
        m_shiftItem = (wxTreeListItem*)NULL;
      bool unselect_others = !(HasFlag(wxTR_MULTIPLE) && (
                                 event.ShiftDown()
                                 || event.ControlDown()
                               ));
      if(SelectItem(item, m_shiftItem, unselect_others)) {
        EnsureVisible(item);
        SetCurrentItem(item);
      }
    }
    if(event.MiddleDown()) {
      bSkip = false;
      SendEvent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, item);
    }
    if(event.RightDown()) {
      bSkip = false;
      SendEvent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, item);
    }
    if(event.RightUp()) {
      wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_MENU, 0);
      nevent.SetPoint(p);
      nevent.SetInt(m_curColumn);
      SendEvent(0, item, &nevent);
    }
    if(m_lastOnSame && event.LeftUp()) {
      if((item == m_curItem) && (m_curColumn != -1) &&
          (m_owner->GetHeaderWindow()->IsColumnEditable(m_curColumn)) &&
          (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))
        ) {
        m_editTimer->Start(RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
        bSkip = false;
      }
      m_lastOnSame = false;
    }
  }
  if(mayDoubleClick && event.LeftDClick()) {
    bSkip = false;
    m_editTimer->Stop();
    m_lastOnSame = false;
    if(SelectItem(item, (wxTreeItemId*)NULL, true)) {
      if(! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item)) {
        if(item && item->HasPlus())
          Toggle(item);
      }
    }
  }
  if(mayDrag) {
    if(m_isDragging) {
      if(event.LeftDown() || event.MiddleDown() || event.RightDown()) {
        bSkip = false;
        m_isDragStarted = m_isDragging = false;
        if(HasCapture())
          ReleaseMouse();
        RefreshSelected();
      } else if(event.Dragging()) {
        ;;
      } else {
        bSkip = false;
        m_isDragStarted = m_isDragging = false;
        if(HasCapture())
          ReleaseMouse();
        RefreshSelected();
        wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, 0);
        event.SetPoint(p);
        event.SetInt(m_curColumn);
        SendEvent(0, item, &event);
      }
    } else if(event.Dragging()) {
      if(m_isDragStarted) {
        const int tolerance = 3;
        int dx = abs(p.x - m_dragStartPos.x);
        int dy = abs(p.y - m_dragStartPos.y);
        if(dx <= tolerance && dy <= tolerance)
          return;
      } else {
        m_dragStartPos = p;
        m_dragCol = GetCurrentColumn();
        m_dragItem = item;
        m_isDragStarted = true;
        return;
      }
      bSkip = false;
      m_isDragging = true;
      RefreshSelected();
      CaptureMouse();
      wxTreeEvent nevent(event.LeftIsDown()
                         ? wxEVT_COMMAND_TREE_BEGIN_DRAG
                         : wxEVT_COMMAND_TREE_BEGIN_RDRAG, 0);
      nevent.SetPoint(p);
      nevent.SetInt(m_dragCol);
      nevent.Veto();
      SendEvent(0, m_dragItem, &nevent);
    }
  }
  if(bSkip)
    event.Skip();
}


void wxTreeListMainWindow::OnIdle(wxIdleEvent &WXUNUSED(event)) {
  if(!m_dirty)
    return;
  m_dirty = false;
  CalculatePositions();
  Refresh();
  AdjustMyScrollbars();
}

void wxTreeListMainWindow::OnScroll(wxScrollWinEvent& event) {
  if(m_owner->GetEventHandler()->ProcessEvent(event))
    return;
  #if !wxCHECK_VERSION(3, 0, 0) && defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
  wxScrolledWindow::OnScroll(event);
  #else
  HandleOnScroll(event);
  #endif
  if(event.GetOrientation() == wxHORIZONTAL) {
    m_owner->GetHeaderWindow()->Refresh();
    m_owner->GetHeaderWindow()->Update();
  }
}

void wxTreeListMainWindow::CalculateSize(wxTreeListItem *item, wxDC &dc) {
  wxCoord text_w = 0;
  wxCoord text_h = 0;
  dc.SetFont(GetItemFont(item));
  dc.GetTextExtent(item->GetText(m_main_column).size() > 0
                   ? item->GetText(m_main_column)
                   : _T(" "),
                   &text_w, &text_h);
  dc.SetFont(m_normalFont);
  int max_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
  if(max_h < 30)
    max_h += 2;

  else
    max_h += max_h / 10;
  item->SetHeight(max_h);
  if(max_h > m_lineHeight)
    m_lineHeight = max_h;
  item->SetWidth(m_imgWidth + text_w + 2);
}

void wxTreeListMainWindow::CalculateLevel(wxTreeListItem *item, wxDC &dc,
    int level, int &y, int x_colstart) {
  int x = x_colstart + MARGIN;
  if(HasFlag(wxTR_LINES_AT_ROOT))
    x += LINEATROOT;
  if(HasButtons())
    x += (m_btnWidth - m_btnWidth2);

  else
    x += (m_indent - m_indent / 2);
  if(HasFlag(wxTR_HIDE_ROOT))
    x += m_indent * (level - 1);

  else
    x += m_indent * level;
  if(HasFlag(wxTR_HIDE_ROOT) && (level == 0))
    goto Recurse;
  CalculateSize(item, dc);
  item->SetX(x);
  item->SetY(y);
  y += GetLineHeight(item);
  if(!item->IsExpanded())
    return;
Recurse:
  wxArrayTreeListItems& children = item->GetChildren();
  long n, count = (long)children.Count();
  ++level;
  for(n = 0; n < count; ++n)
    CalculateLevel(children[n], dc, level, y, x_colstart);
}

void wxTreeListMainWindow::CalculatePositions() {
  if(!m_rootItem)
    return;
  wxClientDC dc(this);
  PrepareDC(dc);
  dc.SetFont(m_normalFont);
  dc.SetPen(m_dottedPen);
  int y = 2;
  int x_colstart = 0;
  for(int i = 0; i < (int)GetMainColumn(); ++i) {
    if(!m_owner->GetHeaderWindow()->IsColumnShown(i))
      continue;
    x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
  }
  CalculateLevel(m_rootItem, dc, 0, y, x_colstart);
}

void wxTreeListMainWindow::RefreshSubtree(wxTreeListItem *item) {
  if(m_dirty)
    return;
  wxClientDC dc(this);
  PrepareDC(dc);
  int cw = 0;
  int ch = 0;
  GetVirtualSize(&cw, &ch);
  wxRect rect;
  rect.x = dc.LogicalToDeviceX(0);
  rect.width = cw;
  rect.y = dc.LogicalToDeviceY(item->GetY() - 2);
  rect.height = ch;
  Refresh(true, &rect);
  AdjustMyScrollbars();
}

void wxTreeListMainWindow::RefreshLine(wxTreeListItem *item) {
  if(m_dirty)
    return;
  wxClientDC dc(this);
  PrepareDC(dc);
  int cw = 0;
  int ch = 0;
  GetVirtualSize(&cw, &ch);
  wxRect rect;
  rect.x = dc.LogicalToDeviceX(0);
  rect.y = dc.LogicalToDeviceY(item->GetY());
  rect.width = cw;
  rect.height = GetLineHeight(item);
  Refresh(true, &rect);
}

void wxTreeListMainWindow::RefreshSelected() {
  if(m_rootItem)
    RefreshSelectedUnder(m_rootItem);
}

void wxTreeListMainWindow::RefreshSelectedUnder(wxTreeListItem *item) {
  if(item->IsSelected())
    RefreshLine(item);
  const wxArrayTreeListItems& children = item->GetChildren();
  long count = (long)children.GetCount();
  for(long n = 0; n < count; n++)
    RefreshSelectedUnder(children[n]);
}



bool wxTreeListMainWindow::SetBackgroundColour(const wxColour& colour) {
  if(!wxWindow::SetBackgroundColour(colour))
    return false;
  Refresh();
  return true;
}

bool wxTreeListMainWindow::SetForegroundColour(const wxColour& colour) {
  if(!wxWindow::SetForegroundColour(colour))
    return false;
  Refresh();
  return true;
}

void wxTreeListMainWindow::SetItemText(const wxTreeItemId& itemId, int column, const wxString& text) {
  wxCHECK_RET(itemId.IsOk(), _T("invalid tree item"));
  wxClientDC dc(this);
  wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
  item->SetText(column, text);
  CalculateSize(item, dc);
  RefreshLine(item);
}

wxString wxTreeListMainWindow::GetItemText(const wxTreeItemId& itemId, int column) const {
  wxCHECK_MSG(itemId.IsOk(), _T(""), _T("invalid tree item"));
  if(IsVirtual())
    return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(), column);
  else
    return ((wxTreeListItem*) itemId.m_pItem)->GetText(column);
}

wxString wxTreeListMainWindow::GetItemText(wxTreeItemData* item, int column) const {
  wxASSERT_MSG(IsVirtual(), _T("can be used only with virtual control"));
  return m_owner->OnGetItemText(item, column);
}

void wxTreeListMainWindow::SetFocus() {
  wxWindow::SetFocus();
}


int wxTreeListMainWindow::GetItemWidth(int column, wxTreeListItem *item) {
  if(!item)
    return 0;
  int w = 0, h = 0;
  wxFont font = GetItemFont(item);
  GetTextExtent(item->GetText(column), &w, &h, NULL, NULL, font.Ok() ? &font : NULL);
  w += 2 * MARGIN;
  int width = w + 2 * MARGIN;
  if(column == GetMainColumn()) {
    width += MARGIN;
    if(HasFlag(wxTR_LINES_AT_ROOT))
      width += LINEATROOT;
    if(HasButtons())
      width += m_btnWidth + LINEATROOT;
    if(item->GetCurrentImage() != NO_IMAGE)
      width += m_imgWidth;
    int level = 0;
    wxTreeListItem *parent = item->GetItemParent();
    wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
    while(parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
      level++;
      parent = parent->GetItemParent();
    }
    if(level)
      width += level * GetIndent();
  }
  return width;
}

int wxTreeListMainWindow::GetBestColumnWidth(int column, wxTreeItemId parent) {
  int maxWidth, h;
  GetClientSize(&maxWidth, &h);
  int width = 0;
  if(!parent.IsOk())
    parent = GetRootItem();
  if(!HasFlag(wxTR_HIDE_ROOT)) {
    int w = GetItemWidth(column, (wxTreeListItem*)parent.m_pItem);
    if(width < w)
      width = w;
    if(width > maxWidth)
      return maxWidth;
  }
  wxTreeItemIdValue cookie = 0;
  wxTreeItemId item = GetFirstChild(parent, cookie);
  while(item.IsOk()) {
    int w = GetItemWidth(column, (wxTreeListItem*)item.m_pItem);
    if(width < w)
      width = w;
    if(width > maxWidth)
      return maxWidth;
    if(((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
      int w = GetBestColumnWidth(column, item);
      if(width < w)
        width = w;
      if(width > maxWidth)
        return maxWidth;
    }
    item = GetNextChild(parent, cookie);
  }
  return width;
}


bool wxTreeListMainWindow::SendEvent(wxEventType event_type, wxTreeListItem *item, wxTreeEvent *event) {
  wxTreeEvent nevent(event_type, 0);
  if(event == NULL) {
    event = &nevent;
    event->SetInt(m_curColumn);
  }
  event->SetEventObject(m_owner);
  event->SetId(m_owner->GetId());
  if(item)
    event->SetItem(item);
  return m_owner->GetEventHandler()->ProcessEvent(*event);
}




IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);

BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
  EVT_SIZE(wxTreeListCtrl::OnSize)
END_EVENT_TABLE();

bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
                            const wxPoint& pos,
                            const wxSize& size,
                            long style, const wxValidator &validator,
                            const wxString& name) {
  long main_style = style & ~(wxSIMPLE_BORDER | wxSUNKEN_BORDER | wxDOUBLE_BORDER |
                              wxRAISED_BORDER | wxSTATIC_BORDER);
  main_style |= wxWANTS_CHARS ;
  long ctrl_style = style & ~(wxVSCROLL | wxHSCROLL);
  if(!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name))
    return false;
  m_main_win = new wxTreeListMainWindow(this, -1, wxPoint(0, 0), size,
                                        main_style, validator);
  m_header_win = new wxTreeListHeaderWindow(this, -1, m_main_win,
      wxPoint(0, 0), wxDefaultSize,
      wxTAB_TRAVERSAL);
  CalculateAndSetHeaderHeight();
  return true;
}

void wxTreeListCtrl::CalculateAndSetHeaderHeight() {
  if(m_header_win) {
    int h;
    #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
    #ifdef __WXMSW__
    h = (int)(wxRendererNative::Get().GetHeaderButtonHeight(m_header_win) * 0.8) + 2;
    #else
    h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
    #endif
    #else
    int w, d;
    m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
    h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
    #endif
    if(h != m_headerHeight) {
      m_headerHeight = h;
      DoHeaderLayout();
    }
  }
}

void wxTreeListCtrl::DoHeaderLayout() {
  int w, h;
  GetClientSize(&w, &h);
  if(m_header_win) {
    m_header_win->SetSize(0, 0, w, m_headerHeight);
    m_header_win->Refresh();
  }
  if(m_main_win)
    m_main_win->SetSize(0, m_headerHeight, w, h - m_headerHeight);
}

void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) {
  DoHeaderLayout();
}

size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }

unsigned int wxTreeListCtrl::GetIndent() const { return m_main_win->GetIndent(); }

void wxTreeListCtrl::SetIndent(unsigned int indent) { m_main_win->SetIndent(indent); }

unsigned int wxTreeListCtrl::GetLineSpacing() const { return m_main_win->GetLineSpacing(); }

void wxTreeListCtrl::SetLineSpacing(unsigned int spacing) { m_main_win->SetLineSpacing(spacing); }

wxImageList* wxTreeListCtrl::GetImageList() const { return m_main_win->GetImageList(); }

wxImageList* wxTreeListCtrl::GetStateImageList() const { return m_main_win->GetStateImageList(); }

wxImageList* wxTreeListCtrl::GetButtonsImageList() const { return m_main_win->GetButtonsImageList(); }

void wxTreeListCtrl::SetImageList(wxImageList* imageList) { m_main_win->SetImageList(imageList); }

void wxTreeListCtrl::SetStateImageList(wxImageList* imageList) { m_main_win->SetStateImageList(imageList); }

void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList) { m_main_win->SetButtonsImageList(imageList); }

void wxTreeListCtrl::AssignImageList(wxImageList* imageList) { m_main_win->AssignImageList(imageList); }

void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList) { m_main_win->AssignStateImageList(imageList); }

void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList) { m_main_win->AssignButtonsImageList(imageList); }



wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const { return m_main_win->GetItemText(item, column); }

int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, wxTreeItemIcon which) const { return m_main_win->GetItemImage(item, which); }
int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column) const { return m_main_win->GetItemImage(item, column); }

wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const { return m_main_win->GetItemData(item); }
wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item, int column) const { return m_main_win->GetItemData(item, column); }

bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const { return m_main_win->GetItemBold(item); }
bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item, int column) const { return m_main_win->GetItemBold(item, column); }

wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const { return m_main_win->GetItemTextColour(item); }
wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item, int column) const { return m_main_win->GetItemTextColour(item, column); }

wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const { return m_main_win->GetItemBackgroundColour(item); }
wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item, int column) const { return m_main_win->GetItemBackgroundColour(item, column); }

wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const { return m_main_win->GetItemFont(item); }
wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item, int column) const { return m_main_win->GetItemFont(item, column); }



void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has) { m_main_win->SetItemHasChildren(item, has); }

void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column, const wxString& text) { m_main_win->SetItemText(item, column, text); }

void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int image, wxTreeItemIcon which) { m_main_win->SetItemImage(item, image, which); }

void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int column, int image) { m_main_win->SetItemImage(item, column, image); }

void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,             wxTreeItemData* data) { m_main_win->SetItemData(item, data); }

void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, int column, wxTreeItemData* data) { m_main_win->SetItemData(item, column, data); }

void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item,             bool bold) { m_main_win->SetItemBold(item, bold); }

void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, int column, bool bold) { m_main_win->SetItemBold(item, column, bold); }

void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,              const wxColour& colour) { m_main_win->SetItemTextColour(item, colour); }

void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour) { m_main_win->SetItemTextColour(item, column, colour); }

void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour) { m_main_win->SetItemBackgroundColour(item, colour); }

void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour) { m_main_win->SetItemBackgroundColour(item, column, colour); }

void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,             const wxFont& font) { m_main_win->SetItemFont(item, font); }

void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, int column, const wxFont& font) { m_main_win->SetItemFont(item, column, font); }



bool wxTreeListCtrl::SetFont(const wxFont& font) {
  if(m_header_win) {
    m_header_win->SetFont(font);
    CalculateAndSetHeaderHeight();
    m_header_win->Refresh();
  }
  if(m_main_win)
    return m_main_win->SetFont(font);

  else
    return false;
}

void wxTreeListCtrl::SetWindowStyle(const long style) {
  if(m_main_win)
    m_main_win->SetWindowStyle(style);
  m_windowStyle = style;
}

long wxTreeListCtrl::GetWindowStyle() const {
  long style = m_windowStyle;
  if(m_main_win)
    style |= m_main_win->GetWindowStyle();
  return style;
}

bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow, bool within) const { return m_main_win->IsVisible(item, fullRow, within); }

bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const { return m_main_win->HasChildren(item); }

bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const { return m_main_win->IsExpanded(item); }

bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const { return m_main_win->IsSelected(item); }

size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec) { return m_main_win->GetChildrenCount(item, rec); }

wxTreeItemId wxTreeListCtrl::GetRootItem() const { return m_main_win->GetRootItem(); }

wxTreeItemId wxTreeListCtrl::GetSelection() const { return m_main_win->GetSelection(); }

size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const { return m_main_win->GetSelections(arr); }

wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const { return m_main_win->GetItemParent(item); }

wxTreeItemId wxTreeListCtrl::GetFirstChild(const wxTreeItemId& item,
    wxTreeItemIdValue& cookie) const { return m_main_win->GetFirstChild(item, cookie); }

wxTreeItemId wxTreeListCtrl::GetNextChild(const wxTreeItemId& item,
    wxTreeItemIdValue& cookie) const { return m_main_win->GetNextChild(item, cookie); }

wxTreeItemId wxTreeListCtrl::GetPrevChild(const wxTreeItemId& item,
    wxTreeItemIdValue& cookie) const { return m_main_win->GetPrevChild(item, cookie); }

wxTreeItemId wxTreeListCtrl::GetLastChild(const wxTreeItemId& item,
    wxTreeItemIdValue& cookie) const { return m_main_win->GetLastChild(item, cookie); }


wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const { return m_main_win->GetNextSibling(item); }

wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const { return m_main_win->GetPrevSibling(item); }

wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const { return m_main_win->GetNext(item, true); }

wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const { return m_main_win->GetPrev(item, true); }

wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const { return m_main_win->GetFirstExpandedItem(); }

wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const { return m_main_win->GetNextExpanded(item); }

wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const { return m_main_win->GetPrevExpanded(item); }

wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const { return GetFirstVisible(fullRow); }
wxTreeItemId wxTreeListCtrl::GetFirstVisible(bool fullRow, bool within) const { return m_main_win->GetFirstVisible(fullRow, within); }

wxTreeItemId wxTreeListCtrl::GetLastVisible(bool fullRow, bool within) const { return m_main_win->GetLastVisible(fullRow, within); }

wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const { return m_main_win->GetNextVisible(item, fullRow, within); }

wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const { return m_main_win->GetPrevVisible(item, fullRow, within); }

wxTreeItemId wxTreeListCtrl::AddRoot(const wxString& text, int image,
                                     int selectedImage, wxTreeItemData* data) { return m_main_win->AddRoot(text, image, selectedImage, data); }

wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
    const wxString& text, int image,
    int selectedImage,
    wxTreeItemData* data) { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }

wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
                                        const wxTreeItemId& previous,
                                        const wxString& text, int image,
                                        int selectedImage,
                                        wxTreeItemData* data) {
  return m_main_win->InsertItem(parent, previous, text, image,
                                selectedImage, data);
}

wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
                                        size_t index,
                                        const wxString& text, int image,
                                        int selectedImage,
                                        wxTreeItemData* data) {
  return m_main_win->InsertItem(parent, index, text, image,
                                selectedImage, data);
}

wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
                                        const wxString& text, int image,
                                        int selectedImage,
                                        wxTreeItemData* data) { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }

void wxTreeListCtrl::Delete(const wxTreeItemId& item) { m_main_win->Delete(item); }

void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item) { m_main_win->DeleteChildren(item); }

void wxTreeListCtrl::DeleteRoot() { m_main_win->DeleteRoot(); }

void wxTreeListCtrl::Expand(const wxTreeItemId& item) { m_main_win->Expand(item); }

void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item) { m_main_win->ExpandAll(item); }

void wxTreeListCtrl::Collapse(const wxTreeItemId& item) { m_main_win->Collapse(item); }

void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item) { m_main_win->CollapseAndReset(item); }

void wxTreeListCtrl::Toggle(const wxTreeItemId& item) { m_main_win->Toggle(item); }

void wxTreeListCtrl::Unselect() { m_main_win->Unselect(); }

void wxTreeListCtrl::UnselectAll() { m_main_win->UnselectAll(); }

bool wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
                                bool unselect_others) { return m_main_win->SelectItem(item, last, unselect_others); }

void wxTreeListCtrl::SelectAll() { m_main_win->SelectAll(); }

void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item) { m_main_win->EnsureVisible(item); }

void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item) { m_main_win->ScrollTo(item); }

wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column) {
  wxPoint p = m_main_win->ScreenToClient(ClientToScreen(pos));
  return m_main_win->HitTest(p, flags, column);
}

bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
                                     bool textOnly) const { return m_main_win->GetBoundingRect(item, rect, textOnly); }

void wxTreeListCtrl::EditLabel(const wxTreeItemId& item, int column)
{ m_main_win->EditLabel(item, column); }

void wxTreeListCtrl::EndEdit(bool isCancelled)
{ m_main_win->EndEdit(isCancelled); }

int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2) {
  return wxStrcmp(GetItemText(item1), GetItemText(item2));
}
int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2, int column) {
  return wxStrcmp(GetItemText(item1, column), GetItemText(item2, column));
}

void wxTreeListCtrl::SortChildren(const wxTreeItemId& item, int column, bool reverseOrder) { m_main_win->SortChildren(item, column, reverseOrder); }

wxTreeItemId wxTreeListCtrl::FindItem(const wxTreeItemId& item, int column, const wxString& str, int mode) { return m_main_win->FindItem(item, column, str, mode); }

void wxTreeListCtrl::SetDragItem(const wxTreeItemId& item) { m_main_win->SetDragItem(item); }

bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour) {
  if(!m_main_win)
    return false;
  return m_main_win->SetBackgroundColour(colour);
}

bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour) {
  if(!m_main_win)
    return false;
  return m_main_win->SetForegroundColour(colour);
}

int wxTreeListCtrl::GetColumnCount() const { return m_main_win->GetColumnCount(); }

void wxTreeListCtrl::SetColumnWidth(int column, int width) {
  m_header_win->SetColumnWidth(column, width);
  m_header_win->Refresh();
}

int wxTreeListCtrl::GetColumnWidth(int column) const { return m_header_win->GetColumnWidth(column); }

void wxTreeListCtrl::SetMainColumn(int column) { m_main_win->SetMainColumn(column); }

int wxTreeListCtrl::GetMainColumn() const { return m_main_win->GetMainColumn(); }

void wxTreeListCtrl::SetColumnText(int column, const wxString& text) {
  m_header_win->SetColumnText(column, text);
  m_header_win->Refresh();
}

wxString wxTreeListCtrl::GetColumnText(int column) const { return m_header_win->GetColumnText(column); }

void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo) {
  m_header_win->AddColumn(colInfo);
  DoHeaderLayout();
}

void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo) {
  m_header_win->InsertColumn(before, colInfo);
  m_header_win->Refresh();
}

void wxTreeListCtrl::RemoveColumn(int column) {
  m_header_win->RemoveColumn(column);
  m_header_win->Refresh();
}

void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo) {
  m_header_win->SetColumn(column, colInfo);
  m_header_win->Refresh();
}

const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const { return m_header_win->GetColumn(column); }

wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) { return m_header_win->GetColumn(column); }

void wxTreeListCtrl::SetColumnImage(int column, int image) {
  m_header_win->SetColumn(column, GetColumn(column).SetImage(image));
  m_header_win->Refresh();
}

int wxTreeListCtrl::GetColumnImage(int column) const {
  return m_header_win->GetColumn(column).GetImage();
}

void wxTreeListCtrl::SetColumnEditable(int column, bool shown) {
  m_header_win->SetColumn(column, GetColumn(column).SetEditable(shown));
}

void wxTreeListCtrl::SetColumnShown(int column, bool shown) {
  wxASSERT_MSG(column != GetMainColumn(), _T("The main column may not be hidden"));
  m_header_win->SetColumn(column, GetColumn(column).SetShown(GetMainColumn() == column ? true : shown));
  m_header_win->Refresh();
}

bool wxTreeListCtrl::IsColumnEditable(int column) const {
  return m_header_win->GetColumn(column).IsEditable();
}

bool wxTreeListCtrl::IsColumnShown(int column) const {
  return m_header_win->GetColumn(column).IsShown();
}

void wxTreeListCtrl::SetColumnAlignment(int column, int flag) {
  m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
  m_header_win->Refresh();
}

int wxTreeListCtrl::GetColumnAlignment(int column) const {
  return m_header_win->GetColumn(column).GetAlignment();
}

void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect) {
  m_main_win->Refresh(erase, rect);
  m_header_win->Refresh(erase, rect);
}

void wxTreeListCtrl::SetFocus() { m_main_win->SetFocus(); }

wxSize wxTreeListCtrl::DoGetBestSize() const {
  wxSize bestSizeHeader = m_header_win->GetBestSize();
  wxSize bestSizeMain = m_main_win->GetBestSize();
  return wxSize(bestSizeHeader.x > bestSizeMain.x ? bestSizeHeader.x : bestSizeMain.x, bestSizeHeader.y + bestSizeMain.y);
}

wxString wxTreeListCtrl::OnGetItemText(wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const {
  return wxEmptyString;
}

void wxTreeListCtrl::SetToolTip(const wxString& tip) {
  m_header_win->SetToolTip(tip);
  m_main_win->SetToolTip(tip);
}

void wxTreeListCtrl::SetToolTip(wxToolTip *tip) {
  m_header_win->SetToolTip(tip);
  m_main_win->SetToolTip(tip);
}

void wxTreeListCtrl::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
  m_main_win->SetItemToolTip(item, tip);
}

void wxTreeListCtrl::SetCurrentItem(const wxTreeItemId& itemId) {
  m_main_win->SetCurrentItem(itemId);
}
